From 25239c6e6220cb3e55d6416e35cff4623ae9921c Mon Sep 17 00:00:00 2001 From: venba-Inspriron-3558 Date: Wed, 18 Jun 2025 16:25:32 +0530 Subject: [PATCH 1/2] report completed --- lib/Screens/reports/misAir.dart | 1036 +++++++++++++++++++ lib/Screens/reports/misForex.dart | 1036 +++++++++++++++++++ lib/Screens/reports/misHotel.dart | 1036 +++++++++++++++++++ lib/Screens/reports/miscellaneousAir.dart | 651 ------------ lib/Screens/reports/miscellaneousForex.dart | 666 ------------ lib/Screens/reports/miscellaneousHotel.dart | 651 ------------ 6 files changed, 3108 insertions(+), 1968 deletions(-) create mode 100644 lib/Screens/reports/misAir.dart create mode 100644 lib/Screens/reports/misForex.dart create mode 100644 lib/Screens/reports/misHotel.dart delete mode 100644 lib/Screens/reports/miscellaneousAir.dart delete mode 100644 lib/Screens/reports/miscellaneousForex.dart delete mode 100644 lib/Screens/reports/miscellaneousHotel.dart diff --git a/lib/Screens/reports/misAir.dart b/lib/Screens/reports/misAir.dart new file mode 100644 index 0000000..516918a --- /dev/null +++ b/lib/Screens/reports/misAir.dart @@ -0,0 +1,1036 @@ +import 'dart:convert'; +import 'dart:core'; +import 'package:go_router/go_router.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:http/http.dart' as http; +import 'package:flutter/material.dart'; +import 'package:frontend/config/apiUrl.dart'; +import 'package:intl/intl.dart'; +import 'package:responsive_builder/responsive_builder.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import '../../routes/custom_appBar.dart'; +import '../../routes/custom_drawer.dart'; +import '../../routes/mainLayout.dart'; +import '../../services/apiService.dart'; +import '../../utils/auth_utils.dart'; +import '../../utils/pagination.dart'; +import '../../widgets/custom_text_field.dart'; + +class AdvancePurchase extends StatefulWidget { + const AdvancePurchase({super.key}); + + @override + _AdvancePurchaseState createState() => _AdvancePurchaseState(); +} + +class _AdvancePurchaseState extends State + with SingleTickerProviderStateMixin { + final ApiService apiService = ApiService(); + + String? userId; + String? orgId; + String? roleUser; + String? token; + + + Color? layoutColor; + Color? bodyColor; + + int currentPage1 = 0; + int itemsPerPage1 = 10; + int currentPage2 = 0; + int itemsPerPage2 = 10; + late TabController _tabController; + final List tabNames = ['Domestic', 'International']; + Map focusNodes = {}; + Map focusStates = {}; + Map textControllers = {}; + Map errorMessages = {}; + // Map advancePurchaseReport = {}; + List> domesticData = []; + List> internationalData = []; + // Map domesticData = {}; + // Map internationalData = {}; + + bool loaderFlag = false; + + @override + void initState() { + super.initState(); + loadInitialData(); + if (!textControllers.containsKey("from_date")) { + textControllers["from_date"] = TextEditingController(); + } + if (!textControllers.containsKey("to_date")) { + textControllers["to_date"] = TextEditingController(); + } + if (!focusNodes.containsKey("from_date")) { + focusNodes["from_date"] = FocusNode(); + } + if (!focusNodes.containsKey("to_date")) { + focusNodes["to_date"] = FocusNode(); + } + if (!focusStates.containsKey("to_date")) { + focusStates["to_date"] = false; + } + if (!focusStates.containsKey("from_date")) { + focusStates["from_date"] = false; + } + + _tabController = TabController(length: 2, vsync: this); + + _tabController.addListener(() { + if (_tabController.indexIsChanging == false) { + // Only fire when tab change is complete + print(" :) :X Selected Tab: ${getTabName(_tabController.index)}"); + } + }); + + // Add focus listeners + focusNodes.forEach((key, focusNode) { + _addFocusListener(focusNode, (focus) { + setState(() { + focusStates[key] = focus; + }); + }); + }); + + getToken(); + // fetchAdvancePurchaseReport(); + } + + String getTabName(int index) { + switch (index) { + case 0: + return "Domestic"; + case 1: + return "International"; + default: + return "Unknown"; + } + } + + void _addFocusListener(FocusNode node, Function(bool) updateState) { + node.addListener(() { + setState(() { + updateState(node.hasFocus); + }); + }); + } + + 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; + }); + + } + + Future initializeData() async { + token = await getToken(); + userId = await getUserId(); + orgId = await getOrgId(); + roleUser = await getRoleUser(); + + + if (token == null || userId == null) { + print("Token or USerId missing"); + return; + } + } + + + Future getUserId() async { + final prefs = await SharedPreferences.getInstance(); + final String? userDataString = prefs.getString('user_data'); + + if (userDataString != null) { + try { + final Map userData = jsonDecode(userDataString); + return userData["user_id"]?.toString(); + } catch (e) { + return null; + } + } + return null; + } + + Future getOrgId() async { + final prefs = await SharedPreferences.getInstance(); + final String? userDataString = prefs.getString('user_data'); + + if (userDataString != null) { + try { + final Map userData = jsonDecode(userDataString); + return userData["org_id"]?.toString(); + } catch (e) { + return null; + } + } + return null; + } + + Future getToken() async { + final prefs = await SharedPreferences.getInstance(); + return prefs.getString('auth_token'); + } + + + Future handleSubmit() async { + errorMessages.remove("from_date"); + errorMessages.remove("to_date"); + setState(() { + domesticData = []; + internationalData = []; + }); + final fromDateText = textControllers["from_date"]?.text; + final toDateText = textControllers["to_date"]?.text; + + if (fromDateText == null || fromDateText.isEmpty || + toDateText == null || toDateText.isEmpty) { + errorMessages["from_date"] = "Required"; + errorMessages["to_date"] = "Required"; + setState(() {}); + return; + } + + // Parse the string to DateTime using the correct format + final dateFormat = DateFormat('dd-MM-yyyy'); + final DateTime fromDate = dateFormat.parse(fromDateText); + final DateTime toDate = dateFormat.parse(toDateText); + + // Check if from date is after to date + if (fromDate.isAfter(toDate)) { + errorMessages["to_date"] = "Invalid Date Range"; + setState(() {}); + return; + } + setState(() { loaderFlag = true; }); + + // Format for API request + final formattedfromDate = DateFormat('yyyy-MM-dd').format(fromDate); + final formattedtoDate = DateFormat('yyyy-MM-dd').format(toDate); + + // Fetch and update + + loaderFlag = true; + try { + final result = await apiService.CallReports( + 'advancePurchaseReport', + formattedfromDate, + formattedtoDate, + ); + setState(() { + domesticData = List>.from(result['data']['domestic'] ?? []); + internationalData = List>.from(result['data']['international'] ?? []); + loaderFlag = false; + }); + } catch (e) { + // handle error + setState(() { + loaderFlag = false; + domesticData = []; + internationalData = []; + }); + } + } + + @override + // Widget build(BuildContext context) { + // // TODO: implement build + // throw UnimplementedError(); + // } + + Widget build(BuildContext context) { + return ResponsiveBuilder( + builder: (context, sizingInfo) { + bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop; + + return Scaffold( + backgroundColor: 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), + // const Expanded(child: Center(child: Text("User Page Content"))), + Expanded(child: buildAdvancePurchaseLayout(isDesktop)) + ], + ), + ), + ); + }, + ); + } + + Widget buildAdvancePurchaseLayout(bool isDesktop) { + return Container( child: buildAdvancePurchaseFormLayout(isDesktop) ); + } + + Widget buildAdvancePurchaseFormLayout(bool isDesktop) { + return Container( + margin: isDesktop ? EdgeInsets.all(10.0) : null, + padding: const EdgeInsets.only(top: 5, bottom: 5, left: 20, right: 20), + // color: Colors.brown, + height: isDesktop + ? MediaQuery.of(context).size.height * 1 + : MediaQuery.of(context).size.height, + decoration: BoxDecoration( + border: isDesktop + ? Border.all(width: 2, color: Colors.white) + : null, + color: isDesktop ? Colors.white : Color(0xFFFCFCFC), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + // ------------------- First Row ------------------- + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Advance Purchase', + style: GoogleFonts.poppins( + fontSize: isDesktop ? 16 : 14, + fontWeight: FontWeight.w600, + color: Colors.black, + ), + ), + Row( + children: [ + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Color(0xFF114D8B), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide(color: Color(0xFF114D8B), width: 2), + ), + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + ), + onPressed: () { + // Your Excel export logic here + }, + child: Row( + children: [ + Text( + "Excel", + style: GoogleFonts.poppins( + fontSize: isDesktop ? 13 : 11, + color: Colors.white, + ), + ), + SizedBox(width: 8), + Icon(Icons.file_present_outlined, size: 15, color: Colors.white), + ], + ), + ), + SizedBox(width: 10), + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Color(0xFF114D8B), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide(color: Color(0xFF114D8B), width: 2), + ), + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + ), + onPressed: () { + // Your PDF export logic here + }, + child: Row( + children: [ + Text( + "PDF", + style: GoogleFonts.poppins( + fontSize: isDesktop ? 13 : 11, + color: Colors.white, + ), + ), + SizedBox(width: 8), + Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), + ], + ), + ), + ], + ), + ], + ), + SizedBox(height: 5), + + // ------------------- Second Row ------------------- + Row( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "From Date *", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74), + ), + ), + SizedBox(height: 5), + CustomTextFieldWrapper( + isFocused: focusStates["from_date"] ?? false, + isDesktop: isDesktop, + child: SizedBox( + height: 40, + child: GestureDetector( + onTap: () async { + final pickedDate = await showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(2000), + lastDate: DateTime(2100), + ); + if (pickedDate != null) { + textControllers["from_date"]?.text = + DateFormat('dd-MM-yyyy').format(pickedDate); + } + }, + child: AbsorbPointer( + child: TextField( + focusNode: focusNodes["from_date"], + controller: textControllers["from_date"], + readOnly: true, + style: const TextStyle(fontSize: 12), + decoration: InputDecoration( + labelText: "Select Date", + labelStyle: const TextStyle( + fontSize: 12, + color: Colors.grey, + ), + floatingLabelBehavior: FloatingLabelBehavior.never, + border: InputBorder.none, + contentPadding: const EdgeInsets.symmetric(vertical: 16), + suffixIcon: const Icon( + Icons.calendar_today, + size: 16, + color: Colors.grey, + ), + ), + ), + ), + ), + ), + ), + if (errorMessages["from_date"] != null) ...[ + SizedBox(height: 5), // Space before error message + Text( + errorMessages["from_date"]!, + style: TextStyle(color: Colors.red, fontSize: 12), + ), + ], + ], + ), + if (isDesktop) Spacer() else SizedBox(height: 8), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "To Date *", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74), + ), + ), + SizedBox(height: 5), + CustomTextFieldWrapper( + isFocused: focusStates["to_date"] ?? false, + isDesktop: isDesktop, + child: SizedBox( + height: 40, + child: GestureDetector( + onTap: () async { + final fromDateText = textControllers["from_date"]?.text; + DateTime? mintoDate; + if (fromDateText != null && fromDateText.isNotEmpty) { + mintoDate = DateFormat('dd-MM-yyyy').parse(fromDateText); + } + + final pickedDate = await showDatePicker( + context: context, + initialDate: mintoDate ?? DateTime.now(), + firstDate: mintoDate ?? DateTime(2000), + lastDate: DateTime(2100), + ); + + if (pickedDate != null) { + textControllers["to_date"]?.text = + DateFormat('dd-MM-yyyy').format(pickedDate); + } + }, + child: AbsorbPointer( + child: TextField( + focusNode: focusNodes["to_date"], + controller: textControllers["to_date"], + readOnly: true, + style: const TextStyle(fontSize: 12), + decoration: const InputDecoration( + labelText: "Select Date", + labelStyle: TextStyle(fontSize: 12, color: Colors.grey), + floatingLabelBehavior: FloatingLabelBehavior.never, + border: InputBorder.none, + contentPadding: EdgeInsets.symmetric(vertical: 16), + suffixIcon: Icon( + Icons.calendar_today, + size: 16, + color: Colors.grey, + ), + ), + ), + ), + ), + ), + ), + if (errorMessages["to_date"] != null) ...[ + SizedBox(height: 5), // Space before error message + Text( + errorMessages["to_date"]!, + style: const TextStyle(color: Colors.red, fontSize: 12), + maxLines: 2, // Allow it to wrap onto two lines + overflow: + TextOverflow.ellipsis, // Add ellipsis if it still overflows + ), + ], + ], + ), + if (isDesktop) Spacer() else SizedBox(height: 8), + SizedBox( + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Color(0xFF114D8B), + foregroundColor: Colors.white, + disabledBackgroundColor: Color(0xFF114D8B), + disabledForegroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide(color: Color(0xFF114D8B), width: 2), + ), + padding: EdgeInsets.symmetric( + horizontal: 20, + vertical: 12, + ), + ), + onPressed: () {handleSubmit();}, + child: Row( + mainAxisSize: + MainAxisSize.min, // Ensures content fits nicely + children: [ + Text( + "Search", + style: GoogleFonts.poppins( + fontSize: isDesktop ? 13 : 11, + ), + ), + SizedBox(width: 8), // spacing between icon and text + Icon( + Icons.search, + size: 15, + color: Colors.white, + ), + ], + ), + ), + ), + ], + ), + SizedBox(height: 5), + + // ------------------- Third Row ------------------- + DefaultTabController( + length: 2, + child: Column( + children: [ + TabBar( + controller: _tabController, + labelColor: Colors.black, + unselectedLabelColor: Colors.grey, + indicatorColor: Color(0xFF114D8B), + tabs: [ + Tab(text: "Domestic"), + Tab(text: "International"), + ], + ), + SizedBox(height: 5), + Container( + // color:Colors.grey, + height: MediaQuery.of(context).size.height * 0.6, + // height: 200, // Or use Expanded for flexible height + child: TabBarView( + controller: _tabController, + children: [ + loaderFlag + ? Center(child: CircularProgressIndicator()) + : domesticData.isEmpty + ? Center( + child: Padding( + padding: EdgeInsets.all(16), + child: Text( + "No data found", + style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w500), + ), + ), + ) + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + /// Title on the left + Expanded( + child: Text( + "Domestic Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", + style: GoogleFonts.poppins( + fontSize: 13, + fontWeight: FontWeight.w500, + color: Colors.grey[700], + ), + overflow: TextOverflow.ellipsis, // Ensures title doesn't overflow + ), + ), + SizedBox(width: 16), + /// Buttons on the right + Row( + children: [ + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Color(0xFF114D8B), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide(color: Color(0xFF114D8B), width: 2), + ), + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + ), + onPressed: () { + // Excel export logic + }, + child: Row( + children: [ + Text( + "Excel", + style: GoogleFonts.poppins( + fontSize: isDesktop ? 13 : 11, + color: Colors.white, + ), + ), + SizedBox(width: 8), + Icon(Icons.file_present_outlined, size: 15, color: Colors.white), + ], + ), + ), + SizedBox(width: 10), + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Color(0xFF114D8B), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide(color: Color(0xFF114D8B), width: 2), + ), + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + ), + onPressed: () { + // PDF export logic + }, + child: Row( + children: [ + Text( + "PDF", + style: GoogleFonts.poppins( + fontSize: isDesktop ? 13 : 11, + color: Colors.white, + ), + ), + SizedBox(width: 8), + Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), + ], + ), + ), + ], + ), + ], + ), + ), + + /* For pagination for list ... */ + // Expanded( + // child: SingleChildScrollView( + // scrollDirection: Axis.horizontal, + // child: SingleChildScrollView( + // scrollDirection: Axis.vertical, + // child: DataTable( + // dividerThickness: 0.5, + // columnSpacing: isDesktop ? 30.0 : 24.0, + // border: TableBorder( + // horizontalInside: BorderSide( + // width: 0.5, + // color: Colors.grey.shade200, + // ), + // ), + // columns: [ + // DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // ], + // rows: domesticData.map((entry) { + // return DataRow(cells: [ + // DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), + // ]); + // }).toList(), + // ), + // ), + // ), + // ), + // -------- Table with Pagination -------- + Expanded( + child: LayoutBuilder( + builder: (context, constraints) { + final double minWidth = isDesktop ? constraints.maxWidth : 1300; + + // Pagination logic + List> paginatedDomestic = domesticData + .skip(currentPage1 * itemsPerPage1) + .take(itemsPerPage1) + .toList(); + + return Column( + children: [ + Expanded( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: ConstrainedBox( + constraints: BoxConstraints(minWidth: minWidth), + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: DataTable( + dividerThickness: 0.5, + columnSpacing: isDesktop ? 30.0 : 24.0, + border: TableBorder( + horizontalInside: BorderSide( + width: 0.5, + color: Colors.grey.shade200, + ), + ), + columns: [ + DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + ], + rows: paginatedDomestic.map((entry) { + return DataRow(cells: [ + DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), + ]); + }).toList(), + ), + ), + ), + ), + ), + + // Pagination controls + PaginationControls( + currentPage: currentPage1, + itemsPerPage: itemsPerPage1, + totalItems: domesticData.length, + activeColor: layoutColor, + onPageChanged: (page) { + setState(() { + currentPage1 = page; + }); + }, + onItemsPerPageChanged: (items) { + setState(() { + itemsPerPage1 = items; + currentPage1 = 0; + }); + }, + ), + ], + ); + }, + ), + ), + ], + ), + + + // International Tab + internationalData.isEmpty + ? Center( + child: Padding( + padding: EdgeInsets.all(16), + child: Text( + "No data found", + style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w500), + ), + ), + ) + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Padding( + // padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), + // child: Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // crossAxisAlignment: CrossAxisAlignment.center, + // children: [ + // /// Title on the left + // Expanded( + // child: Text( + // "International Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", + // style: GoogleFonts.poppins( + // fontSize: 13, + // fontWeight: FontWeight.w500, + // color: Colors.grey[700], + // ), + // overflow: TextOverflow.ellipsis, // Ensures title doesn't overflow + // ), + // ), + // SizedBox(width: 16), + // /// Buttons on the right + // Row( + // children: [ + // ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: Color(0xFF114D8B), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8), + // side: BorderSide(color: Color(0xFF114D8B), width: 2), + // ), + // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + // ), + // onPressed: () { + // // Excel export logic + // }, + // child: Row( + // children: [ + // Text( + // "Excel", + // style: GoogleFonts.poppins( + // fontSize: isDesktop ? 13 : 11, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 8), + // Icon(Icons.file_present_outlined, size: 15, color: Colors.white), + // ], + // ), + // ), + // SizedBox(width: 10), + // ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: Color(0xFF114D8B), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8), + // side: BorderSide(color: Color(0xFF114D8B), width: 2), + // ), + // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + // ), + // onPressed: () { + // // PDF export logic + // }, + // child: Row( + // children: [ + // Text( + // "PDF", + // style: GoogleFonts.poppins( + // fontSize: isDesktop ? 13 : 11, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 8), + // Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), + // ], + // ), + // ), + // ], + // ), + // ], + // ), + // ), + // Expanded( + // child: SingleChildScrollView( + // scrollDirection: Axis.horizontal, + // child: SingleChildScrollView( + // scrollDirection: Axis.vertical, + // child: DataTable( + // dividerThickness: 0.5, + // columnSpacing: isDesktop ? 24.0 : 16.0, + // border: TableBorder( + // horizontalInside: BorderSide( + // width: 0.5, + // color: Colors.grey.shade200, + // ), + // ), + // columns: [ + // DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // ], + // rows: internationalData.map((entry) { + // return DataRow(cells: [ + // DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), + // ]); + // }).toList(), + // ), + // ), + // ), + // ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), + child: Text( + "International Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", + style: GoogleFonts.poppins(fontSize: 13, fontWeight: FontWeight.w500, color: Colors.grey[700]), + ), + ), + Container( + height : isDesktop ? MediaQuery.of(context).size.height * 0.51 : 200, + // color:Colors.amberAccent, + child: LayoutBuilder( + builder: (context, constraints) { + final double minWidth = isDesktop ? constraints.maxWidth : 1300; + + // Pagination logic + List> paginatedInternational = internationalData + .skip(currentPage2 * itemsPerPage2) + .take(itemsPerPage2) + .toList(); + + return Column( + children: [ + Expanded( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: ConstrainedBox( + constraints: BoxConstraints(minWidth: minWidth), + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: DataTable( + dividerThickness: 0.5, + columnSpacing: isDesktop ? 30.0 : 24.0, + border: TableBorder( + horizontalInside: BorderSide( + width: 0.5, + color: Colors.grey.shade200, + ), + ), + columns: [ + DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + ], + rows: paginatedInternational.map((entry) { + return DataRow(cells: [ + DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), + ]); + }).toList(), + ), + ), + ), + ), + ), + + // Pagination controls + PaginationControls( + currentPage: currentPage2, + itemsPerPage: itemsPerPage2, + totalItems: internationalData.length, + activeColor: layoutColor, + onPageChanged: (page) { + setState(() { + currentPage2 = page; + }); + }, + onItemsPerPageChanged: (items) { + setState(() { + itemsPerPage2 = items; + currentPage2 = 0; + }); + }, + ), + ], + ); + }, + ), + ), + ], + ), + ], + ), + ), + ], + ), + ), + // SizedBox(height: 15), + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/Screens/reports/misForex.dart b/lib/Screens/reports/misForex.dart new file mode 100644 index 0000000..516918a --- /dev/null +++ b/lib/Screens/reports/misForex.dart @@ -0,0 +1,1036 @@ +import 'dart:convert'; +import 'dart:core'; +import 'package:go_router/go_router.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:http/http.dart' as http; +import 'package:flutter/material.dart'; +import 'package:frontend/config/apiUrl.dart'; +import 'package:intl/intl.dart'; +import 'package:responsive_builder/responsive_builder.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import '../../routes/custom_appBar.dart'; +import '../../routes/custom_drawer.dart'; +import '../../routes/mainLayout.dart'; +import '../../services/apiService.dart'; +import '../../utils/auth_utils.dart'; +import '../../utils/pagination.dart'; +import '../../widgets/custom_text_field.dart'; + +class AdvancePurchase extends StatefulWidget { + const AdvancePurchase({super.key}); + + @override + _AdvancePurchaseState createState() => _AdvancePurchaseState(); +} + +class _AdvancePurchaseState extends State + with SingleTickerProviderStateMixin { + final ApiService apiService = ApiService(); + + String? userId; + String? orgId; + String? roleUser; + String? token; + + + Color? layoutColor; + Color? bodyColor; + + int currentPage1 = 0; + int itemsPerPage1 = 10; + int currentPage2 = 0; + int itemsPerPage2 = 10; + late TabController _tabController; + final List tabNames = ['Domestic', 'International']; + Map focusNodes = {}; + Map focusStates = {}; + Map textControllers = {}; + Map errorMessages = {}; + // Map advancePurchaseReport = {}; + List> domesticData = []; + List> internationalData = []; + // Map domesticData = {}; + // Map internationalData = {}; + + bool loaderFlag = false; + + @override + void initState() { + super.initState(); + loadInitialData(); + if (!textControllers.containsKey("from_date")) { + textControllers["from_date"] = TextEditingController(); + } + if (!textControllers.containsKey("to_date")) { + textControllers["to_date"] = TextEditingController(); + } + if (!focusNodes.containsKey("from_date")) { + focusNodes["from_date"] = FocusNode(); + } + if (!focusNodes.containsKey("to_date")) { + focusNodes["to_date"] = FocusNode(); + } + if (!focusStates.containsKey("to_date")) { + focusStates["to_date"] = false; + } + if (!focusStates.containsKey("from_date")) { + focusStates["from_date"] = false; + } + + _tabController = TabController(length: 2, vsync: this); + + _tabController.addListener(() { + if (_tabController.indexIsChanging == false) { + // Only fire when tab change is complete + print(" :) :X Selected Tab: ${getTabName(_tabController.index)}"); + } + }); + + // Add focus listeners + focusNodes.forEach((key, focusNode) { + _addFocusListener(focusNode, (focus) { + setState(() { + focusStates[key] = focus; + }); + }); + }); + + getToken(); + // fetchAdvancePurchaseReport(); + } + + String getTabName(int index) { + switch (index) { + case 0: + return "Domestic"; + case 1: + return "International"; + default: + return "Unknown"; + } + } + + void _addFocusListener(FocusNode node, Function(bool) updateState) { + node.addListener(() { + setState(() { + updateState(node.hasFocus); + }); + }); + } + + 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; + }); + + } + + Future initializeData() async { + token = await getToken(); + userId = await getUserId(); + orgId = await getOrgId(); + roleUser = await getRoleUser(); + + + if (token == null || userId == null) { + print("Token or USerId missing"); + return; + } + } + + + Future getUserId() async { + final prefs = await SharedPreferences.getInstance(); + final String? userDataString = prefs.getString('user_data'); + + if (userDataString != null) { + try { + final Map userData = jsonDecode(userDataString); + return userData["user_id"]?.toString(); + } catch (e) { + return null; + } + } + return null; + } + + Future getOrgId() async { + final prefs = await SharedPreferences.getInstance(); + final String? userDataString = prefs.getString('user_data'); + + if (userDataString != null) { + try { + final Map userData = jsonDecode(userDataString); + return userData["org_id"]?.toString(); + } catch (e) { + return null; + } + } + return null; + } + + Future getToken() async { + final prefs = await SharedPreferences.getInstance(); + return prefs.getString('auth_token'); + } + + + Future handleSubmit() async { + errorMessages.remove("from_date"); + errorMessages.remove("to_date"); + setState(() { + domesticData = []; + internationalData = []; + }); + final fromDateText = textControllers["from_date"]?.text; + final toDateText = textControllers["to_date"]?.text; + + if (fromDateText == null || fromDateText.isEmpty || + toDateText == null || toDateText.isEmpty) { + errorMessages["from_date"] = "Required"; + errorMessages["to_date"] = "Required"; + setState(() {}); + return; + } + + // Parse the string to DateTime using the correct format + final dateFormat = DateFormat('dd-MM-yyyy'); + final DateTime fromDate = dateFormat.parse(fromDateText); + final DateTime toDate = dateFormat.parse(toDateText); + + // Check if from date is after to date + if (fromDate.isAfter(toDate)) { + errorMessages["to_date"] = "Invalid Date Range"; + setState(() {}); + return; + } + setState(() { loaderFlag = true; }); + + // Format for API request + final formattedfromDate = DateFormat('yyyy-MM-dd').format(fromDate); + final formattedtoDate = DateFormat('yyyy-MM-dd').format(toDate); + + // Fetch and update + + loaderFlag = true; + try { + final result = await apiService.CallReports( + 'advancePurchaseReport', + formattedfromDate, + formattedtoDate, + ); + setState(() { + domesticData = List>.from(result['data']['domestic'] ?? []); + internationalData = List>.from(result['data']['international'] ?? []); + loaderFlag = false; + }); + } catch (e) { + // handle error + setState(() { + loaderFlag = false; + domesticData = []; + internationalData = []; + }); + } + } + + @override + // Widget build(BuildContext context) { + // // TODO: implement build + // throw UnimplementedError(); + // } + + Widget build(BuildContext context) { + return ResponsiveBuilder( + builder: (context, sizingInfo) { + bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop; + + return Scaffold( + backgroundColor: 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), + // const Expanded(child: Center(child: Text("User Page Content"))), + Expanded(child: buildAdvancePurchaseLayout(isDesktop)) + ], + ), + ), + ); + }, + ); + } + + Widget buildAdvancePurchaseLayout(bool isDesktop) { + return Container( child: buildAdvancePurchaseFormLayout(isDesktop) ); + } + + Widget buildAdvancePurchaseFormLayout(bool isDesktop) { + return Container( + margin: isDesktop ? EdgeInsets.all(10.0) : null, + padding: const EdgeInsets.only(top: 5, bottom: 5, left: 20, right: 20), + // color: Colors.brown, + height: isDesktop + ? MediaQuery.of(context).size.height * 1 + : MediaQuery.of(context).size.height, + decoration: BoxDecoration( + border: isDesktop + ? Border.all(width: 2, color: Colors.white) + : null, + color: isDesktop ? Colors.white : Color(0xFFFCFCFC), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + // ------------------- First Row ------------------- + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Advance Purchase', + style: GoogleFonts.poppins( + fontSize: isDesktop ? 16 : 14, + fontWeight: FontWeight.w600, + color: Colors.black, + ), + ), + Row( + children: [ + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Color(0xFF114D8B), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide(color: Color(0xFF114D8B), width: 2), + ), + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + ), + onPressed: () { + // Your Excel export logic here + }, + child: Row( + children: [ + Text( + "Excel", + style: GoogleFonts.poppins( + fontSize: isDesktop ? 13 : 11, + color: Colors.white, + ), + ), + SizedBox(width: 8), + Icon(Icons.file_present_outlined, size: 15, color: Colors.white), + ], + ), + ), + SizedBox(width: 10), + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Color(0xFF114D8B), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide(color: Color(0xFF114D8B), width: 2), + ), + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + ), + onPressed: () { + // Your PDF export logic here + }, + child: Row( + children: [ + Text( + "PDF", + style: GoogleFonts.poppins( + fontSize: isDesktop ? 13 : 11, + color: Colors.white, + ), + ), + SizedBox(width: 8), + Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), + ], + ), + ), + ], + ), + ], + ), + SizedBox(height: 5), + + // ------------------- Second Row ------------------- + Row( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "From Date *", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74), + ), + ), + SizedBox(height: 5), + CustomTextFieldWrapper( + isFocused: focusStates["from_date"] ?? false, + isDesktop: isDesktop, + child: SizedBox( + height: 40, + child: GestureDetector( + onTap: () async { + final pickedDate = await showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(2000), + lastDate: DateTime(2100), + ); + if (pickedDate != null) { + textControllers["from_date"]?.text = + DateFormat('dd-MM-yyyy').format(pickedDate); + } + }, + child: AbsorbPointer( + child: TextField( + focusNode: focusNodes["from_date"], + controller: textControllers["from_date"], + readOnly: true, + style: const TextStyle(fontSize: 12), + decoration: InputDecoration( + labelText: "Select Date", + labelStyle: const TextStyle( + fontSize: 12, + color: Colors.grey, + ), + floatingLabelBehavior: FloatingLabelBehavior.never, + border: InputBorder.none, + contentPadding: const EdgeInsets.symmetric(vertical: 16), + suffixIcon: const Icon( + Icons.calendar_today, + size: 16, + color: Colors.grey, + ), + ), + ), + ), + ), + ), + ), + if (errorMessages["from_date"] != null) ...[ + SizedBox(height: 5), // Space before error message + Text( + errorMessages["from_date"]!, + style: TextStyle(color: Colors.red, fontSize: 12), + ), + ], + ], + ), + if (isDesktop) Spacer() else SizedBox(height: 8), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "To Date *", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74), + ), + ), + SizedBox(height: 5), + CustomTextFieldWrapper( + isFocused: focusStates["to_date"] ?? false, + isDesktop: isDesktop, + child: SizedBox( + height: 40, + child: GestureDetector( + onTap: () async { + final fromDateText = textControllers["from_date"]?.text; + DateTime? mintoDate; + if (fromDateText != null && fromDateText.isNotEmpty) { + mintoDate = DateFormat('dd-MM-yyyy').parse(fromDateText); + } + + final pickedDate = await showDatePicker( + context: context, + initialDate: mintoDate ?? DateTime.now(), + firstDate: mintoDate ?? DateTime(2000), + lastDate: DateTime(2100), + ); + + if (pickedDate != null) { + textControllers["to_date"]?.text = + DateFormat('dd-MM-yyyy').format(pickedDate); + } + }, + child: AbsorbPointer( + child: TextField( + focusNode: focusNodes["to_date"], + controller: textControllers["to_date"], + readOnly: true, + style: const TextStyle(fontSize: 12), + decoration: const InputDecoration( + labelText: "Select Date", + labelStyle: TextStyle(fontSize: 12, color: Colors.grey), + floatingLabelBehavior: FloatingLabelBehavior.never, + border: InputBorder.none, + contentPadding: EdgeInsets.symmetric(vertical: 16), + suffixIcon: Icon( + Icons.calendar_today, + size: 16, + color: Colors.grey, + ), + ), + ), + ), + ), + ), + ), + if (errorMessages["to_date"] != null) ...[ + SizedBox(height: 5), // Space before error message + Text( + errorMessages["to_date"]!, + style: const TextStyle(color: Colors.red, fontSize: 12), + maxLines: 2, // Allow it to wrap onto two lines + overflow: + TextOverflow.ellipsis, // Add ellipsis if it still overflows + ), + ], + ], + ), + if (isDesktop) Spacer() else SizedBox(height: 8), + SizedBox( + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Color(0xFF114D8B), + foregroundColor: Colors.white, + disabledBackgroundColor: Color(0xFF114D8B), + disabledForegroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide(color: Color(0xFF114D8B), width: 2), + ), + padding: EdgeInsets.symmetric( + horizontal: 20, + vertical: 12, + ), + ), + onPressed: () {handleSubmit();}, + child: Row( + mainAxisSize: + MainAxisSize.min, // Ensures content fits nicely + children: [ + Text( + "Search", + style: GoogleFonts.poppins( + fontSize: isDesktop ? 13 : 11, + ), + ), + SizedBox(width: 8), // spacing between icon and text + Icon( + Icons.search, + size: 15, + color: Colors.white, + ), + ], + ), + ), + ), + ], + ), + SizedBox(height: 5), + + // ------------------- Third Row ------------------- + DefaultTabController( + length: 2, + child: Column( + children: [ + TabBar( + controller: _tabController, + labelColor: Colors.black, + unselectedLabelColor: Colors.grey, + indicatorColor: Color(0xFF114D8B), + tabs: [ + Tab(text: "Domestic"), + Tab(text: "International"), + ], + ), + SizedBox(height: 5), + Container( + // color:Colors.grey, + height: MediaQuery.of(context).size.height * 0.6, + // height: 200, // Or use Expanded for flexible height + child: TabBarView( + controller: _tabController, + children: [ + loaderFlag + ? Center(child: CircularProgressIndicator()) + : domesticData.isEmpty + ? Center( + child: Padding( + padding: EdgeInsets.all(16), + child: Text( + "No data found", + style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w500), + ), + ), + ) + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + /// Title on the left + Expanded( + child: Text( + "Domestic Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", + style: GoogleFonts.poppins( + fontSize: 13, + fontWeight: FontWeight.w500, + color: Colors.grey[700], + ), + overflow: TextOverflow.ellipsis, // Ensures title doesn't overflow + ), + ), + SizedBox(width: 16), + /// Buttons on the right + Row( + children: [ + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Color(0xFF114D8B), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide(color: Color(0xFF114D8B), width: 2), + ), + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + ), + onPressed: () { + // Excel export logic + }, + child: Row( + children: [ + Text( + "Excel", + style: GoogleFonts.poppins( + fontSize: isDesktop ? 13 : 11, + color: Colors.white, + ), + ), + SizedBox(width: 8), + Icon(Icons.file_present_outlined, size: 15, color: Colors.white), + ], + ), + ), + SizedBox(width: 10), + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Color(0xFF114D8B), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide(color: Color(0xFF114D8B), width: 2), + ), + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + ), + onPressed: () { + // PDF export logic + }, + child: Row( + children: [ + Text( + "PDF", + style: GoogleFonts.poppins( + fontSize: isDesktop ? 13 : 11, + color: Colors.white, + ), + ), + SizedBox(width: 8), + Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), + ], + ), + ), + ], + ), + ], + ), + ), + + /* For pagination for list ... */ + // Expanded( + // child: SingleChildScrollView( + // scrollDirection: Axis.horizontal, + // child: SingleChildScrollView( + // scrollDirection: Axis.vertical, + // child: DataTable( + // dividerThickness: 0.5, + // columnSpacing: isDesktop ? 30.0 : 24.0, + // border: TableBorder( + // horizontalInside: BorderSide( + // width: 0.5, + // color: Colors.grey.shade200, + // ), + // ), + // columns: [ + // DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // ], + // rows: domesticData.map((entry) { + // return DataRow(cells: [ + // DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), + // ]); + // }).toList(), + // ), + // ), + // ), + // ), + // -------- Table with Pagination -------- + Expanded( + child: LayoutBuilder( + builder: (context, constraints) { + final double minWidth = isDesktop ? constraints.maxWidth : 1300; + + // Pagination logic + List> paginatedDomestic = domesticData + .skip(currentPage1 * itemsPerPage1) + .take(itemsPerPage1) + .toList(); + + return Column( + children: [ + Expanded( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: ConstrainedBox( + constraints: BoxConstraints(minWidth: minWidth), + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: DataTable( + dividerThickness: 0.5, + columnSpacing: isDesktop ? 30.0 : 24.0, + border: TableBorder( + horizontalInside: BorderSide( + width: 0.5, + color: Colors.grey.shade200, + ), + ), + columns: [ + DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + ], + rows: paginatedDomestic.map((entry) { + return DataRow(cells: [ + DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), + ]); + }).toList(), + ), + ), + ), + ), + ), + + // Pagination controls + PaginationControls( + currentPage: currentPage1, + itemsPerPage: itemsPerPage1, + totalItems: domesticData.length, + activeColor: layoutColor, + onPageChanged: (page) { + setState(() { + currentPage1 = page; + }); + }, + onItemsPerPageChanged: (items) { + setState(() { + itemsPerPage1 = items; + currentPage1 = 0; + }); + }, + ), + ], + ); + }, + ), + ), + ], + ), + + + // International Tab + internationalData.isEmpty + ? Center( + child: Padding( + padding: EdgeInsets.all(16), + child: Text( + "No data found", + style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w500), + ), + ), + ) + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Padding( + // padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), + // child: Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // crossAxisAlignment: CrossAxisAlignment.center, + // children: [ + // /// Title on the left + // Expanded( + // child: Text( + // "International Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", + // style: GoogleFonts.poppins( + // fontSize: 13, + // fontWeight: FontWeight.w500, + // color: Colors.grey[700], + // ), + // overflow: TextOverflow.ellipsis, // Ensures title doesn't overflow + // ), + // ), + // SizedBox(width: 16), + // /// Buttons on the right + // Row( + // children: [ + // ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: Color(0xFF114D8B), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8), + // side: BorderSide(color: Color(0xFF114D8B), width: 2), + // ), + // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + // ), + // onPressed: () { + // // Excel export logic + // }, + // child: Row( + // children: [ + // Text( + // "Excel", + // style: GoogleFonts.poppins( + // fontSize: isDesktop ? 13 : 11, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 8), + // Icon(Icons.file_present_outlined, size: 15, color: Colors.white), + // ], + // ), + // ), + // SizedBox(width: 10), + // ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: Color(0xFF114D8B), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8), + // side: BorderSide(color: Color(0xFF114D8B), width: 2), + // ), + // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + // ), + // onPressed: () { + // // PDF export logic + // }, + // child: Row( + // children: [ + // Text( + // "PDF", + // style: GoogleFonts.poppins( + // fontSize: isDesktop ? 13 : 11, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 8), + // Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), + // ], + // ), + // ), + // ], + // ), + // ], + // ), + // ), + // Expanded( + // child: SingleChildScrollView( + // scrollDirection: Axis.horizontal, + // child: SingleChildScrollView( + // scrollDirection: Axis.vertical, + // child: DataTable( + // dividerThickness: 0.5, + // columnSpacing: isDesktop ? 24.0 : 16.0, + // border: TableBorder( + // horizontalInside: BorderSide( + // width: 0.5, + // color: Colors.grey.shade200, + // ), + // ), + // columns: [ + // DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // ], + // rows: internationalData.map((entry) { + // return DataRow(cells: [ + // DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), + // ]); + // }).toList(), + // ), + // ), + // ), + // ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), + child: Text( + "International Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", + style: GoogleFonts.poppins(fontSize: 13, fontWeight: FontWeight.w500, color: Colors.grey[700]), + ), + ), + Container( + height : isDesktop ? MediaQuery.of(context).size.height * 0.51 : 200, + // color:Colors.amberAccent, + child: LayoutBuilder( + builder: (context, constraints) { + final double minWidth = isDesktop ? constraints.maxWidth : 1300; + + // Pagination logic + List> paginatedInternational = internationalData + .skip(currentPage2 * itemsPerPage2) + .take(itemsPerPage2) + .toList(); + + return Column( + children: [ + Expanded( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: ConstrainedBox( + constraints: BoxConstraints(minWidth: minWidth), + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: DataTable( + dividerThickness: 0.5, + columnSpacing: isDesktop ? 30.0 : 24.0, + border: TableBorder( + horizontalInside: BorderSide( + width: 0.5, + color: Colors.grey.shade200, + ), + ), + columns: [ + DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + ], + rows: paginatedInternational.map((entry) { + return DataRow(cells: [ + DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), + ]); + }).toList(), + ), + ), + ), + ), + ), + + // Pagination controls + PaginationControls( + currentPage: currentPage2, + itemsPerPage: itemsPerPage2, + totalItems: internationalData.length, + activeColor: layoutColor, + onPageChanged: (page) { + setState(() { + currentPage2 = page; + }); + }, + onItemsPerPageChanged: (items) { + setState(() { + itemsPerPage2 = items; + currentPage2 = 0; + }); + }, + ), + ], + ); + }, + ), + ), + ], + ), + ], + ), + ), + ], + ), + ), + // SizedBox(height: 15), + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/Screens/reports/misHotel.dart b/lib/Screens/reports/misHotel.dart new file mode 100644 index 0000000..516918a --- /dev/null +++ b/lib/Screens/reports/misHotel.dart @@ -0,0 +1,1036 @@ +import 'dart:convert'; +import 'dart:core'; +import 'package:go_router/go_router.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:http/http.dart' as http; +import 'package:flutter/material.dart'; +import 'package:frontend/config/apiUrl.dart'; +import 'package:intl/intl.dart'; +import 'package:responsive_builder/responsive_builder.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import '../../routes/custom_appBar.dart'; +import '../../routes/custom_drawer.dart'; +import '../../routes/mainLayout.dart'; +import '../../services/apiService.dart'; +import '../../utils/auth_utils.dart'; +import '../../utils/pagination.dart'; +import '../../widgets/custom_text_field.dart'; + +class AdvancePurchase extends StatefulWidget { + const AdvancePurchase({super.key}); + + @override + _AdvancePurchaseState createState() => _AdvancePurchaseState(); +} + +class _AdvancePurchaseState extends State + with SingleTickerProviderStateMixin { + final ApiService apiService = ApiService(); + + String? userId; + String? orgId; + String? roleUser; + String? token; + + + Color? layoutColor; + Color? bodyColor; + + int currentPage1 = 0; + int itemsPerPage1 = 10; + int currentPage2 = 0; + int itemsPerPage2 = 10; + late TabController _tabController; + final List tabNames = ['Domestic', 'International']; + Map focusNodes = {}; + Map focusStates = {}; + Map textControllers = {}; + Map errorMessages = {}; + // Map advancePurchaseReport = {}; + List> domesticData = []; + List> internationalData = []; + // Map domesticData = {}; + // Map internationalData = {}; + + bool loaderFlag = false; + + @override + void initState() { + super.initState(); + loadInitialData(); + if (!textControllers.containsKey("from_date")) { + textControllers["from_date"] = TextEditingController(); + } + if (!textControllers.containsKey("to_date")) { + textControllers["to_date"] = TextEditingController(); + } + if (!focusNodes.containsKey("from_date")) { + focusNodes["from_date"] = FocusNode(); + } + if (!focusNodes.containsKey("to_date")) { + focusNodes["to_date"] = FocusNode(); + } + if (!focusStates.containsKey("to_date")) { + focusStates["to_date"] = false; + } + if (!focusStates.containsKey("from_date")) { + focusStates["from_date"] = false; + } + + _tabController = TabController(length: 2, vsync: this); + + _tabController.addListener(() { + if (_tabController.indexIsChanging == false) { + // Only fire when tab change is complete + print(" :) :X Selected Tab: ${getTabName(_tabController.index)}"); + } + }); + + // Add focus listeners + focusNodes.forEach((key, focusNode) { + _addFocusListener(focusNode, (focus) { + setState(() { + focusStates[key] = focus; + }); + }); + }); + + getToken(); + // fetchAdvancePurchaseReport(); + } + + String getTabName(int index) { + switch (index) { + case 0: + return "Domestic"; + case 1: + return "International"; + default: + return "Unknown"; + } + } + + void _addFocusListener(FocusNode node, Function(bool) updateState) { + node.addListener(() { + setState(() { + updateState(node.hasFocus); + }); + }); + } + + 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; + }); + + } + + Future initializeData() async { + token = await getToken(); + userId = await getUserId(); + orgId = await getOrgId(); + roleUser = await getRoleUser(); + + + if (token == null || userId == null) { + print("Token or USerId missing"); + return; + } + } + + + Future getUserId() async { + final prefs = await SharedPreferences.getInstance(); + final String? userDataString = prefs.getString('user_data'); + + if (userDataString != null) { + try { + final Map userData = jsonDecode(userDataString); + return userData["user_id"]?.toString(); + } catch (e) { + return null; + } + } + return null; + } + + Future getOrgId() async { + final prefs = await SharedPreferences.getInstance(); + final String? userDataString = prefs.getString('user_data'); + + if (userDataString != null) { + try { + final Map userData = jsonDecode(userDataString); + return userData["org_id"]?.toString(); + } catch (e) { + return null; + } + } + return null; + } + + Future getToken() async { + final prefs = await SharedPreferences.getInstance(); + return prefs.getString('auth_token'); + } + + + Future handleSubmit() async { + errorMessages.remove("from_date"); + errorMessages.remove("to_date"); + setState(() { + domesticData = []; + internationalData = []; + }); + final fromDateText = textControllers["from_date"]?.text; + final toDateText = textControllers["to_date"]?.text; + + if (fromDateText == null || fromDateText.isEmpty || + toDateText == null || toDateText.isEmpty) { + errorMessages["from_date"] = "Required"; + errorMessages["to_date"] = "Required"; + setState(() {}); + return; + } + + // Parse the string to DateTime using the correct format + final dateFormat = DateFormat('dd-MM-yyyy'); + final DateTime fromDate = dateFormat.parse(fromDateText); + final DateTime toDate = dateFormat.parse(toDateText); + + // Check if from date is after to date + if (fromDate.isAfter(toDate)) { + errorMessages["to_date"] = "Invalid Date Range"; + setState(() {}); + return; + } + setState(() { loaderFlag = true; }); + + // Format for API request + final formattedfromDate = DateFormat('yyyy-MM-dd').format(fromDate); + final formattedtoDate = DateFormat('yyyy-MM-dd').format(toDate); + + // Fetch and update + + loaderFlag = true; + try { + final result = await apiService.CallReports( + 'advancePurchaseReport', + formattedfromDate, + formattedtoDate, + ); + setState(() { + domesticData = List>.from(result['data']['domestic'] ?? []); + internationalData = List>.from(result['data']['international'] ?? []); + loaderFlag = false; + }); + } catch (e) { + // handle error + setState(() { + loaderFlag = false; + domesticData = []; + internationalData = []; + }); + } + } + + @override + // Widget build(BuildContext context) { + // // TODO: implement build + // throw UnimplementedError(); + // } + + Widget build(BuildContext context) { + return ResponsiveBuilder( + builder: (context, sizingInfo) { + bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop; + + return Scaffold( + backgroundColor: 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), + // const Expanded(child: Center(child: Text("User Page Content"))), + Expanded(child: buildAdvancePurchaseLayout(isDesktop)) + ], + ), + ), + ); + }, + ); + } + + Widget buildAdvancePurchaseLayout(bool isDesktop) { + return Container( child: buildAdvancePurchaseFormLayout(isDesktop) ); + } + + Widget buildAdvancePurchaseFormLayout(bool isDesktop) { + return Container( + margin: isDesktop ? EdgeInsets.all(10.0) : null, + padding: const EdgeInsets.only(top: 5, bottom: 5, left: 20, right: 20), + // color: Colors.brown, + height: isDesktop + ? MediaQuery.of(context).size.height * 1 + : MediaQuery.of(context).size.height, + decoration: BoxDecoration( + border: isDesktop + ? Border.all(width: 2, color: Colors.white) + : null, + color: isDesktop ? Colors.white : Color(0xFFFCFCFC), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + // ------------------- First Row ------------------- + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Advance Purchase', + style: GoogleFonts.poppins( + fontSize: isDesktop ? 16 : 14, + fontWeight: FontWeight.w600, + color: Colors.black, + ), + ), + Row( + children: [ + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Color(0xFF114D8B), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide(color: Color(0xFF114D8B), width: 2), + ), + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + ), + onPressed: () { + // Your Excel export logic here + }, + child: Row( + children: [ + Text( + "Excel", + style: GoogleFonts.poppins( + fontSize: isDesktop ? 13 : 11, + color: Colors.white, + ), + ), + SizedBox(width: 8), + Icon(Icons.file_present_outlined, size: 15, color: Colors.white), + ], + ), + ), + SizedBox(width: 10), + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Color(0xFF114D8B), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide(color: Color(0xFF114D8B), width: 2), + ), + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + ), + onPressed: () { + // Your PDF export logic here + }, + child: Row( + children: [ + Text( + "PDF", + style: GoogleFonts.poppins( + fontSize: isDesktop ? 13 : 11, + color: Colors.white, + ), + ), + SizedBox(width: 8), + Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), + ], + ), + ), + ], + ), + ], + ), + SizedBox(height: 5), + + // ------------------- Second Row ------------------- + Row( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "From Date *", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74), + ), + ), + SizedBox(height: 5), + CustomTextFieldWrapper( + isFocused: focusStates["from_date"] ?? false, + isDesktop: isDesktop, + child: SizedBox( + height: 40, + child: GestureDetector( + onTap: () async { + final pickedDate = await showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(2000), + lastDate: DateTime(2100), + ); + if (pickedDate != null) { + textControllers["from_date"]?.text = + DateFormat('dd-MM-yyyy').format(pickedDate); + } + }, + child: AbsorbPointer( + child: TextField( + focusNode: focusNodes["from_date"], + controller: textControllers["from_date"], + readOnly: true, + style: const TextStyle(fontSize: 12), + decoration: InputDecoration( + labelText: "Select Date", + labelStyle: const TextStyle( + fontSize: 12, + color: Colors.grey, + ), + floatingLabelBehavior: FloatingLabelBehavior.never, + border: InputBorder.none, + contentPadding: const EdgeInsets.symmetric(vertical: 16), + suffixIcon: const Icon( + Icons.calendar_today, + size: 16, + color: Colors.grey, + ), + ), + ), + ), + ), + ), + ), + if (errorMessages["from_date"] != null) ...[ + SizedBox(height: 5), // Space before error message + Text( + errorMessages["from_date"]!, + style: TextStyle(color: Colors.red, fontSize: 12), + ), + ], + ], + ), + if (isDesktop) Spacer() else SizedBox(height: 8), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "To Date *", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74), + ), + ), + SizedBox(height: 5), + CustomTextFieldWrapper( + isFocused: focusStates["to_date"] ?? false, + isDesktop: isDesktop, + child: SizedBox( + height: 40, + child: GestureDetector( + onTap: () async { + final fromDateText = textControllers["from_date"]?.text; + DateTime? mintoDate; + if (fromDateText != null && fromDateText.isNotEmpty) { + mintoDate = DateFormat('dd-MM-yyyy').parse(fromDateText); + } + + final pickedDate = await showDatePicker( + context: context, + initialDate: mintoDate ?? DateTime.now(), + firstDate: mintoDate ?? DateTime(2000), + lastDate: DateTime(2100), + ); + + if (pickedDate != null) { + textControllers["to_date"]?.text = + DateFormat('dd-MM-yyyy').format(pickedDate); + } + }, + child: AbsorbPointer( + child: TextField( + focusNode: focusNodes["to_date"], + controller: textControllers["to_date"], + readOnly: true, + style: const TextStyle(fontSize: 12), + decoration: const InputDecoration( + labelText: "Select Date", + labelStyle: TextStyle(fontSize: 12, color: Colors.grey), + floatingLabelBehavior: FloatingLabelBehavior.never, + border: InputBorder.none, + contentPadding: EdgeInsets.symmetric(vertical: 16), + suffixIcon: Icon( + Icons.calendar_today, + size: 16, + color: Colors.grey, + ), + ), + ), + ), + ), + ), + ), + if (errorMessages["to_date"] != null) ...[ + SizedBox(height: 5), // Space before error message + Text( + errorMessages["to_date"]!, + style: const TextStyle(color: Colors.red, fontSize: 12), + maxLines: 2, // Allow it to wrap onto two lines + overflow: + TextOverflow.ellipsis, // Add ellipsis if it still overflows + ), + ], + ], + ), + if (isDesktop) Spacer() else SizedBox(height: 8), + SizedBox( + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Color(0xFF114D8B), + foregroundColor: Colors.white, + disabledBackgroundColor: Color(0xFF114D8B), + disabledForegroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide(color: Color(0xFF114D8B), width: 2), + ), + padding: EdgeInsets.symmetric( + horizontal: 20, + vertical: 12, + ), + ), + onPressed: () {handleSubmit();}, + child: Row( + mainAxisSize: + MainAxisSize.min, // Ensures content fits nicely + children: [ + Text( + "Search", + style: GoogleFonts.poppins( + fontSize: isDesktop ? 13 : 11, + ), + ), + SizedBox(width: 8), // spacing between icon and text + Icon( + Icons.search, + size: 15, + color: Colors.white, + ), + ], + ), + ), + ), + ], + ), + SizedBox(height: 5), + + // ------------------- Third Row ------------------- + DefaultTabController( + length: 2, + child: Column( + children: [ + TabBar( + controller: _tabController, + labelColor: Colors.black, + unselectedLabelColor: Colors.grey, + indicatorColor: Color(0xFF114D8B), + tabs: [ + Tab(text: "Domestic"), + Tab(text: "International"), + ], + ), + SizedBox(height: 5), + Container( + // color:Colors.grey, + height: MediaQuery.of(context).size.height * 0.6, + // height: 200, // Or use Expanded for flexible height + child: TabBarView( + controller: _tabController, + children: [ + loaderFlag + ? Center(child: CircularProgressIndicator()) + : domesticData.isEmpty + ? Center( + child: Padding( + padding: EdgeInsets.all(16), + child: Text( + "No data found", + style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w500), + ), + ), + ) + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + /// Title on the left + Expanded( + child: Text( + "Domestic Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", + style: GoogleFonts.poppins( + fontSize: 13, + fontWeight: FontWeight.w500, + color: Colors.grey[700], + ), + overflow: TextOverflow.ellipsis, // Ensures title doesn't overflow + ), + ), + SizedBox(width: 16), + /// Buttons on the right + Row( + children: [ + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Color(0xFF114D8B), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide(color: Color(0xFF114D8B), width: 2), + ), + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + ), + onPressed: () { + // Excel export logic + }, + child: Row( + children: [ + Text( + "Excel", + style: GoogleFonts.poppins( + fontSize: isDesktop ? 13 : 11, + color: Colors.white, + ), + ), + SizedBox(width: 8), + Icon(Icons.file_present_outlined, size: 15, color: Colors.white), + ], + ), + ), + SizedBox(width: 10), + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Color(0xFF114D8B), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide(color: Color(0xFF114D8B), width: 2), + ), + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + ), + onPressed: () { + // PDF export logic + }, + child: Row( + children: [ + Text( + "PDF", + style: GoogleFonts.poppins( + fontSize: isDesktop ? 13 : 11, + color: Colors.white, + ), + ), + SizedBox(width: 8), + Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), + ], + ), + ), + ], + ), + ], + ), + ), + + /* For pagination for list ... */ + // Expanded( + // child: SingleChildScrollView( + // scrollDirection: Axis.horizontal, + // child: SingleChildScrollView( + // scrollDirection: Axis.vertical, + // child: DataTable( + // dividerThickness: 0.5, + // columnSpacing: isDesktop ? 30.0 : 24.0, + // border: TableBorder( + // horizontalInside: BorderSide( + // width: 0.5, + // color: Colors.grey.shade200, + // ), + // ), + // columns: [ + // DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // ], + // rows: domesticData.map((entry) { + // return DataRow(cells: [ + // DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), + // ]); + // }).toList(), + // ), + // ), + // ), + // ), + // -------- Table with Pagination -------- + Expanded( + child: LayoutBuilder( + builder: (context, constraints) { + final double minWidth = isDesktop ? constraints.maxWidth : 1300; + + // Pagination logic + List> paginatedDomestic = domesticData + .skip(currentPage1 * itemsPerPage1) + .take(itemsPerPage1) + .toList(); + + return Column( + children: [ + Expanded( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: ConstrainedBox( + constraints: BoxConstraints(minWidth: minWidth), + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: DataTable( + dividerThickness: 0.5, + columnSpacing: isDesktop ? 30.0 : 24.0, + border: TableBorder( + horizontalInside: BorderSide( + width: 0.5, + color: Colors.grey.shade200, + ), + ), + columns: [ + DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + ], + rows: paginatedDomestic.map((entry) { + return DataRow(cells: [ + DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), + ]); + }).toList(), + ), + ), + ), + ), + ), + + // Pagination controls + PaginationControls( + currentPage: currentPage1, + itemsPerPage: itemsPerPage1, + totalItems: domesticData.length, + activeColor: layoutColor, + onPageChanged: (page) { + setState(() { + currentPage1 = page; + }); + }, + onItemsPerPageChanged: (items) { + setState(() { + itemsPerPage1 = items; + currentPage1 = 0; + }); + }, + ), + ], + ); + }, + ), + ), + ], + ), + + + // International Tab + internationalData.isEmpty + ? Center( + child: Padding( + padding: EdgeInsets.all(16), + child: Text( + "No data found", + style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w500), + ), + ), + ) + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Padding( + // padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), + // child: Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // crossAxisAlignment: CrossAxisAlignment.center, + // children: [ + // /// Title on the left + // Expanded( + // child: Text( + // "International Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", + // style: GoogleFonts.poppins( + // fontSize: 13, + // fontWeight: FontWeight.w500, + // color: Colors.grey[700], + // ), + // overflow: TextOverflow.ellipsis, // Ensures title doesn't overflow + // ), + // ), + // SizedBox(width: 16), + // /// Buttons on the right + // Row( + // children: [ + // ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: Color(0xFF114D8B), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8), + // side: BorderSide(color: Color(0xFF114D8B), width: 2), + // ), + // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + // ), + // onPressed: () { + // // Excel export logic + // }, + // child: Row( + // children: [ + // Text( + // "Excel", + // style: GoogleFonts.poppins( + // fontSize: isDesktop ? 13 : 11, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 8), + // Icon(Icons.file_present_outlined, size: 15, color: Colors.white), + // ], + // ), + // ), + // SizedBox(width: 10), + // ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: Color(0xFF114D8B), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8), + // side: BorderSide(color: Color(0xFF114D8B), width: 2), + // ), + // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + // ), + // onPressed: () { + // // PDF export logic + // }, + // child: Row( + // children: [ + // Text( + // "PDF", + // style: GoogleFonts.poppins( + // fontSize: isDesktop ? 13 : 11, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 8), + // Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), + // ], + // ), + // ), + // ], + // ), + // ], + // ), + // ), + // Expanded( + // child: SingleChildScrollView( + // scrollDirection: Axis.horizontal, + // child: SingleChildScrollView( + // scrollDirection: Axis.vertical, + // child: DataTable( + // dividerThickness: 0.5, + // columnSpacing: isDesktop ? 24.0 : 16.0, + // border: TableBorder( + // horizontalInside: BorderSide( + // width: 0.5, + // color: Colors.grey.shade200, + // ), + // ), + // columns: [ + // DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // ], + // rows: internationalData.map((entry) { + // return DataRow(cells: [ + // DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), + // ]); + // }).toList(), + // ), + // ), + // ), + // ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), + child: Text( + "International Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", + style: GoogleFonts.poppins(fontSize: 13, fontWeight: FontWeight.w500, color: Colors.grey[700]), + ), + ), + Container( + height : isDesktop ? MediaQuery.of(context).size.height * 0.51 : 200, + // color:Colors.amberAccent, + child: LayoutBuilder( + builder: (context, constraints) { + final double minWidth = isDesktop ? constraints.maxWidth : 1300; + + // Pagination logic + List> paginatedInternational = internationalData + .skip(currentPage2 * itemsPerPage2) + .take(itemsPerPage2) + .toList(); + + return Column( + children: [ + Expanded( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: ConstrainedBox( + constraints: BoxConstraints(minWidth: minWidth), + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: DataTable( + dividerThickness: 0.5, + columnSpacing: isDesktop ? 30.0 : 24.0, + border: TableBorder( + horizontalInside: BorderSide( + width: 0.5, + color: Colors.grey.shade200, + ), + ), + columns: [ + DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + ], + rows: paginatedInternational.map((entry) { + return DataRow(cells: [ + DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), + ]); + }).toList(), + ), + ), + ), + ), + ), + + // Pagination controls + PaginationControls( + currentPage: currentPage2, + itemsPerPage: itemsPerPage2, + totalItems: internationalData.length, + activeColor: layoutColor, + onPageChanged: (page) { + setState(() { + currentPage2 = page; + }); + }, + onItemsPerPageChanged: (items) { + setState(() { + itemsPerPage2 = items; + currentPage2 = 0; + }); + }, + ), + ], + ); + }, + ), + ), + ], + ), + ], + ), + ), + ], + ), + ), + // SizedBox(height: 15), + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/Screens/reports/miscellaneousAir.dart b/lib/Screens/reports/miscellaneousAir.dart deleted file mode 100644 index 591551d..0000000 --- a/lib/Screens/reports/miscellaneousAir.dart +++ /dev/null @@ -1,651 +0,0 @@ -import 'dart:convert'; -import 'dart:core'; -import 'package:go_router/go_router.dart'; -import 'package:google_fonts/google_fonts.dart'; -import 'package:http/http.dart' as http; -import 'package:flutter/material.dart'; -import 'package:frontend/config/apiUrl.dart'; -import 'package:intl/intl.dart'; -import 'package:responsive_builder/responsive_builder.dart'; -import 'package:shared_preferences/shared_preferences.dart'; - -import '../../routes/custom_appBar.dart'; -import '../../routes/custom_drawer.dart'; -import '../../routes/mainLayout.dart'; -import '../../services/apiService.dart'; -import '../../utils/auth_utils.dart'; -import '../../widgets/custom_text_field.dart'; - -class MiscellaneousAir extends StatefulWidget { - const MiscellaneousAir({super.key}); - - @override - _MiscellaneousAirState createState() => _MiscellaneousAirState(); -} - -class _MiscellaneousAirState extends State { - final ApiService apiService = ApiService(); - - String? userId; - String? orgId; - String? roleUser; - String? token; - - Color? layoutColor; - Color? bodyColor; - - Map focusNodes = {}; - Map focusStates = {}; - Map textControllers = {}; - Map errorMessages = {}; - // Map MiscellaneousAirReport = {}; - List> domesticData = []; - List> internationData = []; - // Map domesticData = {}; - // Map internationData = {}; - - @override - void initState() { - super.initState(); - - if (!textControllers.containsKey("from_date")) { - textControllers["from_date"] = TextEditingController(); - } - if (!textControllers.containsKey("to_date")) { - textControllers["to_date"] = TextEditingController(); - } - if (!focusNodes.containsKey("from_date")) { - focusNodes["from_date"] = FocusNode(); - } - if (!focusNodes.containsKey("to_date")) { - focusNodes["to_date"] = FocusNode(); - } - if (!focusStates.containsKey("to_date")) { - focusStates["to_date"] = false; - } - if (!focusStates.containsKey("from_date")) { - focusStates["from_date"] = false; - } - - - - // Add focus listeners - focusNodes.forEach((key, focusNode) { - _addFocusListener(focusNode, (focus) { - setState(() { - focusStates[key] = focus; - }); - }); - }); - - getToken(); - // fetchMiscellaneousAirReport(); - } - void _addFocusListener(FocusNode node, Function(bool) updateState) { - node.addListener(() { - setState(() { - updateState(node.hasFocus); - }); - }); - } - - 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; - }); - - } - - Future initializeData() async { - token = await getToken(); - userId = await getUserId(); - orgId = await getOrgId(); - roleUser = await getRoleUser(); - - - if (token == null || userId == null) { - print("Token or USerId missing"); - return; - } - } - - - Future getUserId() async { - final prefs = await SharedPreferences.getInstance(); - final String? userDataString = prefs.getString('user_data'); - - if (userDataString != null) { - try { - final Map userData = jsonDecode(userDataString); - return userData["user_id"]?.toString(); - } catch (e) { - return null; - } - } - return null; - } - - Future getOrgId() async { - final prefs = await SharedPreferences.getInstance(); - final String? userDataString = prefs.getString('user_data'); - - if (userDataString != null) { - try { - final Map userData = jsonDecode(userDataString); - return userData["org_id"]?.toString(); - } catch (e) { - return null; - } - } - return null; - } - - Future getToken() async { - final prefs = await SharedPreferences.getInstance(); - return prefs.getString('auth_token'); - } - - - Future handleSubmit() async { - errorMessages.remove("from_date"); - errorMessages.remove("to_date"); - - final fromDateText = textControllers["from_date"]?.text; - final toDateText = textControllers["to_date"]?.text; - - if (fromDateText == null || fromDateText.isEmpty || - toDateText == null || toDateText.isEmpty) { - errorMessages["from_date"] = "Required"; - errorMessages["to_date"] = "Required"; - setState(() {}); - return; - } - - // Parse the string to DateTime using the correct format - final dateFormat = DateFormat('dd-MM-yyyy'); - final DateTime fromDate = dateFormat.parse(fromDateText); - final DateTime toDate = dateFormat.parse(toDateText); - - // Check if from date is after to date - if (fromDate.isAfter(toDate)) { - errorMessages["to_date"] = "Invalid Date Range"; - setState(() {}); - return; - } - - // Format for API request - final formattedfromDate = DateFormat('yyyy-MM-dd').format(fromDate); - final formattedtoDate = DateFormat('yyyy-MM-dd').format(toDate); - - // Fetch and update - final result = await apiService.CallReports( - 'misAirReport', - formattedfromDate, - formattedtoDate, - ); - - setState(() { - domesticData = List>.from(result['data']['domestic'] ?? []); - internationData = List>.from(result['data']['international'] ?? []); - }); - } - - @override - // Widget build(BuildContext context) { - // // TODO: implement build - // throw UnimplementedError(); - // } - - Widget build(BuildContext context) { - return ResponsiveBuilder( - builder: (context, sizingInfo) { - bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop; - - return Scaffold( - backgroundColor: 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), - // const Expanded(child: Center(child: Text("User Page Content"))), - Expanded(child: buildMiscellaneousAirLayout(isDesktop)) - ], - ), - ), - ); - }, - ); - } - - Widget buildMiscellaneousAirLayout(bool isDesktop) { - return Container( child: buildMiscellaneousAirFormLayout(isDesktop) ); - } - - Widget buildMiscellaneousAirFormLayout(bool isDesktop) { - return Container( - margin: isDesktop ? EdgeInsets.all(10.0) : null, - padding: const EdgeInsets.only(top: 15, bottom: 15, left: 20, right: 20), - height: isDesktop - ? MediaQuery.of(context).size.height * 0.98 - : MediaQuery.of(context).size.height, - decoration: BoxDecoration( - border: isDesktop - ? Border.all(width: 2, color: Colors.white) - : null, - color: isDesktop ? Colors.white : Color(0xFFFCFCFC), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - // ------------------- First Row ------------------- - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Miscellaneous Air', - style: GoogleFonts.poppins( - fontSize: isDesktop ? 16 : 14, - fontWeight: FontWeight.w600, - color: Colors.black, - ), - ), - Row( - children: [ - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFF114D8B), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide(color: Color(0xFF114D8B), width: 2), - ), - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), - ), - onPressed: () { - // Your Excel export logic here - }, - child: Row( - children: [ - Text( - "Excel", - style: GoogleFonts.poppins( - fontSize: isDesktop ? 13 : 11, - color: Colors.white, - ), - ), - SizedBox(width: 8), - Icon(Icons.file_present_outlined, size: 15, color: Colors.white), - ], - ), - ), - SizedBox(width: 10), - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFF114D8B), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide(color: Color(0xFF114D8B), width: 2), - ), - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), - ), - onPressed: () { - // Your PDF export logic here - }, - child: Row( - children: [ - Text( - "PDF", - style: GoogleFonts.poppins( - fontSize: isDesktop ? 13 : 11, - color: Colors.white, - ), - ), - SizedBox(width: 8), - Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), - ], - ), - ), - ], - ), - ], - ), - SizedBox(height: 15), - - // ------------------- Second Row ------------------- - Row( - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "From Date *", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74), - ), - ), - SizedBox(height: 5), - CustomTextFieldWrapper( - isFocused: focusStates["from_date"] ?? false, - isDesktop: isDesktop, - child: SizedBox( - height: 40, - child: GestureDetector( - onTap: () async { - final pickedDate = await showDatePicker( - context: context, - initialDate: DateTime.now(), - firstDate: DateTime(2000), - lastDate: DateTime(2100), - ); - if (pickedDate != null) { - textControllers["from_date"]?.text = - DateFormat('dd-MM-yyyy').format(pickedDate); - } - }, - child: AbsorbPointer( - child: TextField( - focusNode: focusNodes["from_date"], - controller: textControllers["from_date"], - readOnly: true, - style: const TextStyle(fontSize: 12), - decoration: InputDecoration( - labelText: "Select Date", - labelStyle: const TextStyle( - fontSize: 12, - color: Colors.grey, - ), - floatingLabelBehavior: FloatingLabelBehavior.never, - border: InputBorder.none, - contentPadding: const EdgeInsets.symmetric(vertical: 16), - suffixIcon: const Icon( - Icons.calendar_today, - size: 16, - color: Colors.grey, - ), - ), - ), - ), - ), - ), - ), - if (errorMessages["from_date"] != null) ...[ - SizedBox(height: 5), // Space before error message - Text( - errorMessages["from_date"]!, - style: TextStyle(color: Colors.red, fontSize: 12), - ), - ], - ], - ), - if (isDesktop) Spacer() else SizedBox(height: 8), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "To Date *", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74), - ), - ), - SizedBox(height: 5), - CustomTextFieldWrapper( - isFocused: focusStates["to_date"] ?? false, - isDesktop: isDesktop, - child: SizedBox( - height: 40, - child: GestureDetector( - onTap: () async { - final fromDateText = textControllers["from_date"]?.text; - DateTime? mintoDate; - if (fromDateText != null && fromDateText.isNotEmpty) { - mintoDate = DateFormat('dd-MM-yyyy').parse(fromDateText); - } - - final pickedDate = await showDatePicker( - context: context, - initialDate: mintoDate ?? DateTime.now(), - firstDate: mintoDate ?? DateTime(2000), - lastDate: DateTime(2100), - ); - - if (pickedDate != null) { - textControllers["to_date"]?.text = - DateFormat('dd-MM-yyyy').format(pickedDate); - } - }, - child: AbsorbPointer( - child: TextField( - focusNode: focusNodes["to_date"], - controller: textControllers["to_date"], - readOnly: true, - style: const TextStyle(fontSize: 12), - decoration: const InputDecoration( - labelText: "Select Date", - labelStyle: TextStyle(fontSize: 12, color: Colors.grey), - floatingLabelBehavior: FloatingLabelBehavior.never, - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(vertical: 16), - suffixIcon: Icon( - Icons.calendar_today, - size: 16, - color: Colors.grey, - ), - ), - ), - ), - ), - ), - ), - if (errorMessages["to_date"] != null) ...[ - SizedBox(height: 5), // Space before error message - Text( - errorMessages["to_date"]!, - style: const TextStyle(color: Colors.red, fontSize: 12), - maxLines: 2, // Allow it to wrap onto two lines - overflow: - TextOverflow.ellipsis, // Add ellipsis if it still overflows - ), - ], - ], - ), - if (isDesktop) Spacer() else SizedBox(height: 8), - SizedBox( - child: ElevatedButton( - onPressed: () { - handleSubmit(); - // You can get text from commentController.text - // Navigator.of(context).pop(); // Close the modal - }, - style: ElevatedButton.styleFrom( - // backgroundColor: layoutColor, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - child: Text( - 'Search', - style: GoogleFonts.poppins( - fontSize: 11, - color: Colors.white, - ), - ), - ), - ), - ], - ), - SizedBox(height: 15), - - // ------------------- Third Row ------------------- - DefaultTabController( - length: 2, - child: Column( - children: [ - TabBar( - labelColor: Colors.black, - unselectedLabelColor: Colors.grey, - indicatorColor: Color(0xFF114D8B), - tabs: [ - Tab(text: "Domestic"), - Tab(text: "International"), - ], - ), - SizedBox(height: 10), - Container( - height: 200, // Or use Expanded for flexible height - child: TabBarView( - children: [ - // Domestic Tab - domesticData.isEmpty - ? Center( - child: Padding( - padding: EdgeInsets.all(16), - child: Text( - "No data found", - style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w500), - ), - ), - ) - : Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), - child: Text( - "Domestic Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", - style: GoogleFonts.poppins(fontSize: 13, fontWeight: FontWeight.w500, color: Colors.grey[700]), - ), - ), - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: DataTable( - dividerThickness: 0.5, - columnSpacing: isDesktop ? 24.0 : 16.0, - border: TableBorder( - horizontalInside: BorderSide( - width: 0.5, - color: Colors.grey.shade200, - ), - ), - columns: [ - DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - ], - rows: domesticData.map((entry) { - return DataRow(cells: [ - DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), - ]); - }).toList(), - ), - ), - ), - ], - ), - - // International Tab - internationData.isEmpty - ? Center( - child: Padding( - padding: EdgeInsets.all(16), - child: Text( - "No data found", - style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w500), - ), - ), - ) - : Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), - child: Text( - "International Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", - style: GoogleFonts.poppins(fontSize: 13, fontWeight: FontWeight.w500, color: Colors.grey[700]), - ), - ), - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: DataTable( - dividerThickness: 0.5, - columnSpacing: isDesktop ? 24.0 : 16.0, - border: TableBorder( - horizontalInside: BorderSide( - width: 0.5, - color: Colors.grey.shade200, - ), - ), - columns: [ - DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - ], - rows: internationData.map((entry) { - return DataRow(cells: [ - DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), - ]); - }).toList(), - ), - ), - ), - ], - ), - ], - ), - ), - ], - ), - ), - SizedBox(height: 15), - - ], - ), - ); - } - -} - diff --git a/lib/Screens/reports/miscellaneousForex.dart b/lib/Screens/reports/miscellaneousForex.dart deleted file mode 100644 index 14c2ca7..0000000 --- a/lib/Screens/reports/miscellaneousForex.dart +++ /dev/null @@ -1,666 +0,0 @@ -import 'dart:convert'; -import 'dart:core'; -import 'package:go_router/go_router.dart'; -import 'package:google_fonts/google_fonts.dart'; -import 'package:http/http.dart' as http; -import 'package:flutter/material.dart'; -import 'package:frontend/config/apiUrl.dart'; -import 'package:intl/intl.dart'; -import 'package:responsive_builder/responsive_builder.dart'; -import 'package:shared_preferences/shared_preferences.dart'; - -import '../../routes/custom_appBar.dart'; -import '../../routes/custom_drawer.dart'; -import '../../routes/mainLayout.dart'; -import '../../services/apiService.dart'; -import '../../utils/auth_utils.dart'; -import '../../widgets/custom_text_field.dart'; - -class MiscellaneousForex extends StatefulWidget { - const MiscellaneousForex({super.key}); - - @override - _MiscellaneousForexState createState() => _MiscellaneousForexState(); -} - -class _MiscellaneousForexState extends State { - final ApiService apiService = ApiService(); - - String? userId; - String? orgId; - String? roleUser; - String? token; - - Color? layoutColor; - Color? bodyColor; - - Map focusNodes = {}; - Map focusStates = {}; - Map textControllers = {}; - Map errorMessages = {}; - // Map MiscellaneousForexReport = {}; - List> domesticData = []; - List> internationData = []; - // Map domesticData = {}; - // Map internationData = {}; - - @override - void initState() { - super.initState(); - - if (!textControllers.containsKey("from_date")) { - textControllers["from_date"] = TextEditingController(); - } - if (!textControllers.containsKey("to_date")) { - textControllers["to_date"] = TextEditingController(); - } - if (!focusNodes.containsKey("from_date")) { - focusNodes["from_date"] = FocusNode(); - } - if (!focusNodes.containsKey("to_date")) { - focusNodes["to_date"] = FocusNode(); - } - if (!focusStates.containsKey("to_date")) { - focusStates["to_date"] = false; - } - if (!focusStates.containsKey("from_date")) { - focusStates["from_date"] = false; - } - - - - // Add focus listeners - focusNodes.forEach((key, focusNode) { - _addFocusListener(focusNode, (focus) { - setState(() { - focusStates[key] = focus; - }); - }); - }); - - getToken(); - // fetchMiscellaneousForexReport(); - } - void _addFocusListener(FocusNode node, Function(bool) updateState) { - node.addListener(() { - setState(() { - updateState(node.hasFocus); - }); - }); - } - - 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; - }); - - } - - Future initializeData() async { - token = await getToken(); - userId = await getUserId(); - orgId = await getOrgId(); - roleUser = await getRoleUser(); - - - if (token == null || userId == null) { - print("Token or USerId missing"); - return; - } - } - - - Future getUserId() async { - final prefs = await SharedPreferences.getInstance(); - final String? userDataString = prefs.getString('user_data'); - - if (userDataString != null) { - try { - final Map userData = jsonDecode(userDataString); - return userData["user_id"]?.toString(); - } catch (e) { - return null; - } - } - return null; - } - - Future getOrgId() async { - final prefs = await SharedPreferences.getInstance(); - final String? userDataString = prefs.getString('user_data'); - - if (userDataString != null) { - try { - final Map userData = jsonDecode(userDataString); - return userData["org_id"]?.toString(); - } catch (e) { - return null; - } - } - return null; - } - - Future getToken() async { - final prefs = await SharedPreferences.getInstance(); - return prefs.getString('auth_token'); - } - - - Future handleSubmit() async { - errorMessages.remove("from_date"); - errorMessages.remove("to_date"); - - final fromDateText = textControllers["from_date"]?.text; - final toDateText = textControllers["to_date"]?.text; - - if (fromDateText == null || fromDateText.isEmpty || - toDateText == null || toDateText.isEmpty) { - errorMessages["from_date"] = "Required"; - errorMessages["to_date"] = "Required"; - setState(() {}); - return; - } - - // Parse the string to DateTime using the correct format - final dateFormat = DateFormat('dd-MM-yyyy'); - final DateTime fromDate = dateFormat.parse(fromDateText); - final DateTime toDate = dateFormat.parse(toDateText); - - // Check if from date is after to date - if (fromDate.isAfter(toDate)) { - errorMessages["to_date"] = "Invalid Date Range"; - setState(() {}); - return; - } - - // Format for API request - final formattedfromDate = DateFormat('yyyy-MM-dd').format(fromDate); - final formattedtoDate = DateFormat('yyyy-MM-dd').format(toDate); - - // Fetch and update - final result = await apiService.CallReports( - 'misForexReport', - formattedfromDate, - formattedtoDate, - ); - - setState(() { - domesticData = List>.from(result['data']['domestic'] ?? []); - internationData = List>.from(result['data']['international'] ?? []); - }); - } - - @override - // Widget build(BuildContext context) { - // // TODO: implement build - // throw UnimplementedError(); - // } - - Widget build(BuildContext context) { - return ResponsiveBuilder( - builder: (context, sizingInfo) { - bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop; - - return Scaffold( - backgroundColor: 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), - // const Expanded(child: Center(child: Text("User Page Content"))), - Expanded(child: buildMiscellaneousForexLayout(isDesktop)) - ], - ), - ), - ); - }, - ); - } - - Widget buildMiscellaneousForexLayout(bool isDesktop) { - return Container( child: buildMiscellaneousForexFormLayout(isDesktop) ); - } - - Widget buildMiscellaneousForexFormLayout(bool isDesktop) { - return Container( - margin: isDesktop ? EdgeInsets.all(10.0) : null, - padding: const EdgeInsets.only(top: 15, bottom: 15, left: 20, right: 20), - height: isDesktop - ? MediaQuery.of(context).size.height * 0.98 - : MediaQuery.of(context).size.height, - decoration: BoxDecoration( - border: isDesktop - ? Border.all(width: 2, color: Colors.white) - : null, - color: isDesktop ? Colors.white : Color(0xFFFCFCFC), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - // ------------------- First Row ------------------- - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Miscellaneous Forex', - style: GoogleFonts.poppins( - fontSize: isDesktop ? 16 : 14, - fontWeight: FontWeight.w600, - color: Colors.black, - ), - ), - Row( - children: [ - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFF114D8B), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide(color: Color(0xFF114D8B), width: 2), - ), - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), - ), - onPressed: () { - // Your Excel export logic here - }, - child: Row( - children: [ - Text( - "Excel", - style: GoogleFonts.poppins( - fontSize: isDesktop ? 13 : 11, - color: Colors.white, - ), - ), - SizedBox(width: 8), - Icon(Icons.file_present_outlined, size: 15, color: Colors.white), - ], - ), - ), - SizedBox(width: 10), - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFF114D8B), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide(color: Color(0xFF114D8B), width: 2), - ), - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), - ), - onPressed: () { - // Your PDF export logic here - }, - child: Row( - children: [ - Text( - "PDF", - style: GoogleFonts.poppins( - fontSize: isDesktop ? 13 : 11, - color: Colors.white, - ), - ), - SizedBox(width: 8), - Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), - ], - ), - ), - ], - ), - ], - ), - SizedBox(height: 15), - - // ------------------- Second Row ------------------- - Row( - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "From Date *", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74), - ), - ), - SizedBox(height: 5), - CustomTextFieldWrapper( - isFocused: focusStates["from_date"] ?? false, - isDesktop: isDesktop, - child: SizedBox( - height: 40, - child: GestureDetector( - onTap: () async { - final pickedDate = await showDatePicker( - context: context, - initialDate: DateTime.now(), - firstDate: DateTime(2000), - lastDate: DateTime(2100), - ); - if (pickedDate != null) { - textControllers["from_date"]?.text = - DateFormat('dd-MM-yyyy').format(pickedDate); - } - }, - child: AbsorbPointer( - child: TextField( - focusNode: focusNodes["from_date"], - controller: textControllers["from_date"], - readOnly: true, - style: const TextStyle(fontSize: 12), - decoration: InputDecoration( - labelText: "Select Date", - labelStyle: const TextStyle( - fontSize: 12, - color: Colors.grey, - ), - floatingLabelBehavior: FloatingLabelBehavior.never, - border: InputBorder.none, - contentPadding: const EdgeInsets.symmetric(vertical: 16), - suffixIcon: const Icon( - Icons.calendar_today, - size: 16, - color: Colors.grey, - ), - ), - ), - ), - ), - ), - ), - if (errorMessages["from_date"] != null) ...[ - SizedBox(height: 5), // Space before error message - Text( - errorMessages["from_date"]!, - style: TextStyle(color: Colors.red, fontSize: 12), - ), - ], - ], - ), - if (isDesktop) Spacer() else SizedBox(height: 8), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "To Date *", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74), - ), - ), - SizedBox(height: 5), - CustomTextFieldWrapper( - isFocused: focusStates["to_date"] ?? false, - isDesktop: isDesktop, - child: SizedBox( - height: 40, - child: GestureDetector( - onTap: () async { - final fromDateText = textControllers["from_date"]?.text; - DateTime? mintoDate; - if (fromDateText != null && fromDateText.isNotEmpty) { - mintoDate = DateFormat('dd-MM-yyyy').parse(fromDateText); - } - - final pickedDate = await showDatePicker( - context: context, - initialDate: mintoDate ?? DateTime.now(), - firstDate: mintoDate ?? DateTime(2000), - lastDate: DateTime(2100), - ); - - if (pickedDate != null) { - textControllers["to_date"]?.text = - DateFormat('dd-MM-yyyy').format(pickedDate); - } - }, - child: AbsorbPointer( - child: TextField( - focusNode: focusNodes["to_date"], - controller: textControllers["to_date"], - readOnly: true, - style: const TextStyle(fontSize: 12), - decoration: const InputDecoration( - labelText: "Select Date", - labelStyle: TextStyle(fontSize: 12, color: Colors.grey), - floatingLabelBehavior: FloatingLabelBehavior.never, - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(vertical: 16), - suffixIcon: Icon( - Icons.calendar_today, - size: 16, - color: Colors.grey, - ), - ), - ), - ), - ), - ), - ), - if (errorMessages["to_date"] != null) ...[ - SizedBox(height: 5), // Space before error message - Text( - errorMessages["to_date"]!, - style: const TextStyle(color: Colors.red, fontSize: 12), - maxLines: 2, // Allow it to wrap onto two lines - overflow: - TextOverflow.ellipsis, // Add ellipsis if it still overflows - ), - ], - ], - ), - if (isDesktop) Spacer() else SizedBox(height: 8), - SizedBox( - child: ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFF114D8B), - foregroundColor: Colors.white, - disabledBackgroundColor: Color(0xFF114D8B), - disabledForegroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide(color: Color(0xFF114D8B), width: 2), - ), - padding: EdgeInsets.symmetric( - horizontal: 20, - vertical: 12, - ), - ), - onPressed: () {handleSubmit();}, - child: Row( - mainAxisSize: - MainAxisSize.min, // Ensures content fits nicely - children: [ - Text( - "Search", - style: GoogleFonts.poppins( - fontSize: isDesktop ? 13 : 11, - ), - ), - SizedBox(width: 8), // spacing between icon and text - Icon( - Icons.search, - size: 15, - color: Colors.white, - ), - ], - ), - ), - ), - ], - ), - SizedBox(height: 15), - - // ------------------- Third Row ------------------- - DefaultTabController( - length: 2, - child: Column( - children: [ - TabBar( - labelColor: Colors.black, - unselectedLabelColor: Colors.grey, - indicatorColor: Color(0xFF114D8B), - tabs: [ - Tab(text: "Domestic"), - Tab(text: "International"), - ], - ), - SizedBox(height: 10), - Container( - height: 200, // Or use Expanded for flexible height - child: TabBarView( - children: [ - // Domestic Tab - domesticData.isEmpty - ? Center( - child: Padding( - padding: EdgeInsets.all(16), - child: Text( - "No data found", - style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w500), - ), - ), - ) - : Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), - child: Text( - "Domestic Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", - style: GoogleFonts.poppins(fontSize: 13, fontWeight: FontWeight.w500, color: Colors.grey[700]), - ), - ), - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: DataTable( - dividerThickness: 0.5, - columnSpacing: isDesktop ? 24.0 : 16.0, - border: TableBorder( - horizontalInside: BorderSide( - width: 0.5, - color: Colors.grey.shade200, - ), - ), - columns: [ - DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - ], - rows: domesticData.map((entry) { - return DataRow(cells: [ - DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), - ]); - }).toList(), - ), - ), - ), - ], - ), - - // International Tab - internationData.isEmpty - ? Center( - child: Padding( - padding: EdgeInsets.all(16), - child: Text( - "No data found", - style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w500), - ), - ), - ) - : Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), - child: Text( - "International Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", - style: GoogleFonts.poppins(fontSize: 13, fontWeight: FontWeight.w500, color: Colors.grey[700]), - ), - ), - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: DataTable( - dividerThickness: 0.5, - columnSpacing: isDesktop ? 24.0 : 16.0, - border: TableBorder( - horizontalInside: BorderSide( - width: 0.5, - color: Colors.grey.shade200, - ), - ), - columns: [ - DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - ], - rows: internationData.map((entry) { - return DataRow(cells: [ - DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), - ]); - }).toList(), - ), - ), - ), - ], - ), - ], - ), - ), - ], - ), - ), - SizedBox(height: 15), - - ], - ), - ); - } - -} - diff --git a/lib/Screens/reports/miscellaneousHotel.dart b/lib/Screens/reports/miscellaneousHotel.dart deleted file mode 100644 index b81bd07..0000000 --- a/lib/Screens/reports/miscellaneousHotel.dart +++ /dev/null @@ -1,651 +0,0 @@ -import 'dart:convert'; -import 'dart:core'; -import 'package:go_router/go_router.dart'; -import 'package:google_fonts/google_fonts.dart'; -import 'package:http/http.dart' as http; -import 'package:flutter/material.dart'; -import 'package:frontend/config/apiUrl.dart'; -import 'package:intl/intl.dart'; -import 'package:responsive_builder/responsive_builder.dart'; -import 'package:shared_preferences/shared_preferences.dart'; - -import '../../routes/custom_appBar.dart'; -import '../../routes/custom_drawer.dart'; -import '../../routes/mainLayout.dart'; -import '../../services/apiService.dart'; -import '../../utils/auth_utils.dart'; -import '../../widgets/custom_text_field.dart'; - -class MiscellaneousHotel extends StatefulWidget { - const MiscellaneousHotel({super.key}); - - @override - _MiscellaneousHotelState createState() => _MiscellaneousHotelState(); -} - -class _MiscellaneousHotelState extends State { - final ApiService apiService = ApiService(); - - String? userId; - String? orgId; - String? roleUser; - String? token; - - Color? layoutColor; - Color? bodyColor; - - Map focusNodes = {}; - Map focusStates = {}; - Map textControllers = {}; - Map errorMessages = {}; - // Map MiscellaneousHotelReport = {}; - List> domesticData = []; - List> internationData = []; - // Map domesticData = {}; - // Map internationData = {}; - - @override - void initState() { - super.initState(); - - if (!textControllers.containsKey("from_date")) { - textControllers["from_date"] = TextEditingController(); - } - if (!textControllers.containsKey("to_date")) { - textControllers["to_date"] = TextEditingController(); - } - if (!focusNodes.containsKey("from_date")) { - focusNodes["from_date"] = FocusNode(); - } - if (!focusNodes.containsKey("to_date")) { - focusNodes["to_date"] = FocusNode(); - } - if (!focusStates.containsKey("to_date")) { - focusStates["to_date"] = false; - } - if (!focusStates.containsKey("from_date")) { - focusStates["from_date"] = false; - } - - - - // Add focus listeners - focusNodes.forEach((key, focusNode) { - _addFocusListener(focusNode, (focus) { - setState(() { - focusStates[key] = focus; - }); - }); - }); - - getToken(); - // fetchMiscellaneousHotelReport(); - } - void _addFocusListener(FocusNode node, Function(bool) updateState) { - node.addListener(() { - setState(() { - updateState(node.hasFocus); - }); - }); - } - - 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; - }); - - } - - Future initializeData() async { - token = await getToken(); - userId = await getUserId(); - orgId = await getOrgId(); - roleUser = await getRoleUser(); - - - if (token == null || userId == null) { - print("Token or USerId missing"); - return; - } - } - - - Future getUserId() async { - final prefs = await SharedPreferences.getInstance(); - final String? userDataString = prefs.getString('user_data'); - - if (userDataString != null) { - try { - final Map userData = jsonDecode(userDataString); - return userData["user_id"]?.toString(); - } catch (e) { - return null; - } - } - return null; - } - - Future getOrgId() async { - final prefs = await SharedPreferences.getInstance(); - final String? userDataString = prefs.getString('user_data'); - - if (userDataString != null) { - try { - final Map userData = jsonDecode(userDataString); - return userData["org_id"]?.toString(); - } catch (e) { - return null; - } - } - return null; - } - - Future getToken() async { - final prefs = await SharedPreferences.getInstance(); - return prefs.getString('auth_token'); - } - - - Future handleSubmit() async { - errorMessages.remove("from_date"); - errorMessages.remove("to_date"); - - final fromDateText = textControllers["from_date"]?.text; - final toDateText = textControllers["to_date"]?.text; - - if (fromDateText == null || fromDateText.isEmpty || - toDateText == null || toDateText.isEmpty) { - errorMessages["from_date"] = "Required"; - errorMessages["to_date"] = "Required"; - setState(() {}); - return; - } - - // Parse the string to DateTime using the correct format - final dateFormat = DateFormat('dd-MM-yyyy'); - final DateTime fromDate = dateFormat.parse(fromDateText); - final DateTime toDate = dateFormat.parse(toDateText); - - // Check if from date is after to date - if (fromDate.isAfter(toDate)) { - errorMessages["to_date"] = "Invalid Date Range"; - setState(() {}); - return; - } - - // Format for API request - final formattedfromDate = DateFormat('yyyy-MM-dd').format(fromDate); - final formattedtoDate = DateFormat('yyyy-MM-dd').format(toDate); - - // Fetch and update - final result = await apiService.CallReports( - 'misHotelReport', - formattedfromDate, - formattedtoDate, - ); - - setState(() { - domesticData = List>.from(result['data']['domestic'] ?? []); - internationData = List>.from(result['data']['international'] ?? []); - }); - } - - @override - // Widget build(BuildContext context) { - // // TODO: implement build - // throw UnimplementedError(); - // } - - Widget build(BuildContext context) { - return ResponsiveBuilder( - builder: (context, sizingInfo) { - bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop; - - return Scaffold( - backgroundColor: 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), - // const Expanded(child: Center(child: Text("User Page Content"))), - Expanded(child: buildMiscellaneousHotelLayout(isDesktop)) - ], - ), - ), - ); - }, - ); - } - - Widget buildMiscellaneousHotelLayout(bool isDesktop) { - return Container( child: buildMiscellaneousHotelFormLayout(isDesktop) ); - } - - Widget buildMiscellaneousHotelFormLayout(bool isDesktop) { - return Container( - margin: isDesktop ? EdgeInsets.all(10.0) : null, - padding: const EdgeInsets.only(top: 15, bottom: 15, left: 20, right: 20), - height: isDesktop - ? MediaQuery.of(context).size.height * 0.98 - : MediaQuery.of(context).size.height, - decoration: BoxDecoration( - border: isDesktop - ? Border.all(width: 2, color: Colors.white) - : null, - color: isDesktop ? Colors.white : Color(0xFFFCFCFC), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - // ------------------- First Row ------------------- - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Miscellaneous Hotel', - style: GoogleFonts.poppins( - fontSize: isDesktop ? 16 : 14, - fontWeight: FontWeight.w600, - color: Colors.black, - ), - ), - Row( - children: [ - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFF114D8B), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide(color: Color(0xFF114D8B), width: 2), - ), - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), - ), - onPressed: () { - // Your Excel export logic here - }, - child: Row( - children: [ - Text( - "Excel", - style: GoogleFonts.poppins( - fontSize: isDesktop ? 13 : 11, - color: Colors.white, - ), - ), - SizedBox(width: 8), - Icon(Icons.file_present_outlined, size: 15, color: Colors.white), - ], - ), - ), - SizedBox(width: 10), - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFF114D8B), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide(color: Color(0xFF114D8B), width: 2), - ), - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), - ), - onPressed: () { - // Your PDF export logic here - }, - child: Row( - children: [ - Text( - "PDF", - style: GoogleFonts.poppins( - fontSize: isDesktop ? 13 : 11, - color: Colors.white, - ), - ), - SizedBox(width: 8), - Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), - ], - ), - ), - ], - ), - ], - ), - SizedBox(height: 15), - - // ------------------- Second Row ------------------- - Row( - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "From Date *", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74), - ), - ), - SizedBox(height: 5), - CustomTextFieldWrapper( - isFocused: focusStates["from_date"] ?? false, - isDesktop: isDesktop, - child: SizedBox( - height: 40, - child: GestureDetector( - onTap: () async { - final pickedDate = await showDatePicker( - context: context, - initialDate: DateTime.now(), - firstDate: DateTime(2000), - lastDate: DateTime(2100), - ); - if (pickedDate != null) { - textControllers["from_date"]?.text = - DateFormat('dd-MM-yyyy').format(pickedDate); - } - }, - child: AbsorbPointer( - child: TextField( - focusNode: focusNodes["from_date"], - controller: textControllers["from_date"], - readOnly: true, - style: const TextStyle(fontSize: 12), - decoration: InputDecoration( - labelText: "Select Date", - labelStyle: const TextStyle( - fontSize: 12, - color: Colors.grey, - ), - floatingLabelBehavior: FloatingLabelBehavior.never, - border: InputBorder.none, - contentPadding: const EdgeInsets.symmetric(vertical: 16), - suffixIcon: const Icon( - Icons.calendar_today, - size: 16, - color: Colors.grey, - ), - ), - ), - ), - ), - ), - ), - if (errorMessages["from_date"] != null) ...[ - SizedBox(height: 5), // Space before error message - Text( - errorMessages["from_date"]!, - style: TextStyle(color: Colors.red, fontSize: 12), - ), - ], - ], - ), - if (isDesktop) Spacer() else SizedBox(height: 8), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "To Date *", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74), - ), - ), - SizedBox(height: 5), - CustomTextFieldWrapper( - isFocused: focusStates["to_date"] ?? false, - isDesktop: isDesktop, - child: SizedBox( - height: 40, - child: GestureDetector( - onTap: () async { - final fromDateText = textControllers["from_date"]?.text; - DateTime? mintoDate; - if (fromDateText != null && fromDateText.isNotEmpty) { - mintoDate = DateFormat('dd-MM-yyyy').parse(fromDateText); - } - - final pickedDate = await showDatePicker( - context: context, - initialDate: mintoDate ?? DateTime.now(), - firstDate: mintoDate ?? DateTime(2000), - lastDate: DateTime(2100), - ); - - if (pickedDate != null) { - textControllers["to_date"]?.text = - DateFormat('dd-MM-yyyy').format(pickedDate); - } - }, - child: AbsorbPointer( - child: TextField( - focusNode: focusNodes["to_date"], - controller: textControllers["to_date"], - readOnly: true, - style: const TextStyle(fontSize: 12), - decoration: const InputDecoration( - labelText: "Select Date", - labelStyle: TextStyle(fontSize: 12, color: Colors.grey), - floatingLabelBehavior: FloatingLabelBehavior.never, - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(vertical: 16), - suffixIcon: Icon( - Icons.calendar_today, - size: 16, - color: Colors.grey, - ), - ), - ), - ), - ), - ), - ), - if (errorMessages["to_date"] != null) ...[ - SizedBox(height: 5), // Space before error message - Text( - errorMessages["to_date"]!, - style: const TextStyle(color: Colors.red, fontSize: 12), - maxLines: 2, // Allow it to wrap onto two lines - overflow: - TextOverflow.ellipsis, // Add ellipsis if it still overflows - ), - ], - ], - ), - if (isDesktop) Spacer() else SizedBox(height: 8), - SizedBox( - child: ElevatedButton( - onPressed: () { - handleSubmit(); - // You can get text from commentController.text - // Navigator.of(context).pop(); // Close the modal - }, - style: ElevatedButton.styleFrom( - // backgroundColor: layoutColor, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - child: Text( - 'Search', - style: GoogleFonts.poppins( - fontSize: 11, - color: Colors.white, - ), - ), - ), - ), - ], - ), - SizedBox(height: 15), - - // ------------------- Third Row ------------------- - DefaultTabController( - length: 2, - child: Column( - children: [ - TabBar( - labelColor: Colors.black, - unselectedLabelColor: Colors.grey, - indicatorColor: Color(0xFF114D8B), - tabs: [ - Tab(text: "Domestic"), - Tab(text: "International"), - ], - ), - SizedBox(height: 10), - Container( - height: 200, // Or use Expanded for flexible height - child: TabBarView( - children: [ - // Domestic Tab - domesticData.isEmpty - ? Center( - child: Padding( - padding: EdgeInsets.all(16), - child: Text( - "No data found", - style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w500), - ), - ), - ) - : Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), - child: Text( - "Domestic Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", - style: GoogleFonts.poppins(fontSize: 13, fontWeight: FontWeight.w500, color: Colors.grey[700]), - ), - ), - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: DataTable( - dividerThickness: 0.5, - columnSpacing: isDesktop ? 24.0 : 16.0, - border: TableBorder( - horizontalInside: BorderSide( - width: 0.5, - color: Colors.grey.shade200, - ), - ), - columns: [ - DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - ], - rows: domesticData.map((entry) { - return DataRow(cells: [ - DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), - ]); - }).toList(), - ), - ), - ), - ], - ), - - // International Tab - internationData.isEmpty - ? Center( - child: Padding( - padding: EdgeInsets.all(16), - child: Text( - "No data found", - style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w500), - ), - ), - ) - : Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), - child: Text( - "International Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", - style: GoogleFonts.poppins(fontSize: 13, fontWeight: FontWeight.w500, color: Colors.grey[700]), - ), - ), - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: DataTable( - dividerThickness: 0.5, - columnSpacing: isDesktop ? 24.0 : 16.0, - border: TableBorder( - horizontalInside: BorderSide( - width: 0.5, - color: Colors.grey.shade200, - ), - ), - columns: [ - DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - ], - rows: internationData.map((entry) { - return DataRow(cells: [ - DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), - ]); - }).toList(), - ), - ), - ), - ], - ), - ], - ), - ), - ], - ), - ), - SizedBox(height: 15), - - ], - ), - ); - } - -} - From ce9bcb113b6893182d9c01a7c89fe88027f18d3a Mon Sep 17 00:00:00 2001 From: venba-Inspriron-3558 Date: Wed, 18 Jun 2025 16:26:09 +0530 Subject: [PATCH 2/2] report completed 2 --- lib/Screens/policy/policy_list.dart | 2 + lib/Screens/reports/advancePurchase.dart | 1397 ++++++++++++++---- lib/Screens/reports/guestHouse.dart | 1369 ++++++++++++++--- lib/Screens/reports/misAir.dart | 1613 ++++++++++++++------- lib/Screens/reports/misForex.dart | 1136 +++++++-------- lib/Screens/reports/misHotel.dart | 401 +++-- lib/Screens/reports/reportList.dart | 193 +-- lib/Screens/reports/servicesAnalysis.dart | 1081 +++++++++++--- lib/config/apiUrl.dart | 4 +- lib/routes/custom_appBar.dart | 10 +- lib/routes/custom_router.dart | 12 +- lib/services/apiService.dart | 57 +- 12 files changed, 5167 insertions(+), 2108 deletions(-) diff --git a/lib/Screens/policy/policy_list.dart b/lib/Screens/policy/policy_list.dart index 709c2b1..c359f00 100644 --- a/lib/Screens/policy/policy_list.dart +++ b/lib/Screens/policy/policy_list.dart @@ -94,6 +94,8 @@ class _PolicyListState extends State { futurePolicy.then((object) { setState(() { allPolicy = object; + filteredPolicy = object; + searchController.text = ""; }); }); // Wait for futurePlans to be fetched and update allPlans diff --git a/lib/Screens/reports/advancePurchase.dart b/lib/Screens/reports/advancePurchase.dart index 37fb63b..4c2cec3 100644 --- a/lib/Screens/reports/advancePurchase.dart +++ b/lib/Screens/reports/advancePurchase.dart @@ -1,5 +1,7 @@ import 'dart:convert'; import 'dart:core'; +import 'dart:typed_data'; + import 'package:go_router/go_router.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; @@ -8,12 +10,13 @@ import 'package:frontend/config/apiUrl.dart'; import 'package:intl/intl.dart'; import 'package:responsive_builder/responsive_builder.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:universal_html/html.dart' as html; import '../../routes/custom_appBar.dart'; import '../../routes/custom_drawer.dart'; -import '../../routes/mainLayout.dart'; import '../../services/apiService.dart'; import '../../utils/auth_utils.dart'; +import '../../utils/pagination.dart'; import '../../widgets/custom_text_field.dart'; class AdvancePurchase extends StatefulWidget { @@ -23,7 +26,8 @@ class AdvancePurchase extends StatefulWidget { _AdvancePurchaseState createState() => _AdvancePurchaseState(); } -class _AdvancePurchaseState extends State { +class _AdvancePurchaseState extends State + with SingleTickerProviderStateMixin { final ApiService apiService = ApiService(); String? userId; @@ -34,40 +38,50 @@ class _AdvancePurchaseState extends State { Color? layoutColor; Color? bodyColor; + int currentPage1 = 0; + int itemsPerPage1 = 10; + int currentPage2 = 0; + int itemsPerPage2 = 10; + late TabController _tabController; + String selectedTabName = 'domestic'; Map focusNodes = {}; Map focusStates = {}; Map textControllers = {}; Map errorMessages = {}; // Map advancePurchaseReport = {}; List> domesticData = []; - List> internationData = []; + List> internationalData = []; // Map domesticData = {}; - // Map internationData = {}; + // Map internationalData = {}; + // List> filteredDomestic = []; + List filteredInternational = []; + TextEditingController searchController = TextEditingController(); + + bool loaderFlag = false; @override void initState() { super.initState(); + loadInitialData(); + _checkAuthAndLoadData(); + if (!textControllers.containsKey("from_date")) { textControllers["from_date"] = TextEditingController(); } + if (!textControllers.containsKey("to_date")) { textControllers["to_date"] = TextEditingController(); } + if (!focusNodes.containsKey("from_date")) { focusNodes["from_date"] = FocusNode(); } + if (!focusNodes.containsKey("to_date")) { focusNodes["to_date"] = FocusNode(); } + if (!focusStates.containsKey("to_date")) { focusStates["to_date"] = false; } + if (!focusStates.containsKey("from_date")) { focusStates["from_date"] = false; } - if (!textControllers.containsKey("from_date")) { - textControllers["from_date"] = TextEditingController(); - } - if (!textControllers.containsKey("to_date")) { - textControllers["to_date"] = TextEditingController(); - } - if (!focusNodes.containsKey("from_date")) { - focusNodes["from_date"] = FocusNode(); - } - if (!focusNodes.containsKey("to_date")) { - focusNodes["to_date"] = FocusNode(); - } - if (!focusStates.containsKey("to_date")) { - focusStates["to_date"] = false; - } - if (!focusStates.containsKey("from_date")) { - focusStates["from_date"] = false; - } - + _tabController = TabController(length: 2, vsync: this); + _tabController.addListener(() { + if (_tabController.indexIsChanging == false) { + // Only fire when tab change is complete + setState(() { + selectedTabName = getTabName(_tabController.index); + }); + print(" :) :X Selected Tab: ${getTabName(_tabController.index)}"); + } + }); // Add focus listeners focusNodes.forEach((key, focusNode) { @@ -81,6 +95,17 @@ class _AdvancePurchaseState extends State { getToken(); // fetchAdvancePurchaseReport(); } + + String getTabName(int index) { + switch (index) { + case 0: return "domestic"; + case 1: return "international"; + default: + // return "Unknown"; + return "domestic"; + } + } + void _addFocusListener(FocusNode node, Function(bool) updateState) { node.addListener(() { setState(() { @@ -94,13 +119,16 @@ class _AdvancePurchaseState extends State { String? bodyStringColor = await getBodyColor(); setState(() { - layoutColor = layoutString != null ? Color(int.parse(layoutString)) - : Colors.redAccent; + layoutColor = + layoutString != null + ? Color(int.parse(layoutString)) + : Colors.redAccent; - bodyColor = bodyStringColor != null ? Color(int.parse(bodyStringColor)) - : Colors.white; + bodyColor = + bodyStringColor != null + ? Color(int.parse(bodyStringColor)) + : Colors.white; }); - } Future initializeData() async { @@ -109,13 +137,31 @@ class _AdvancePurchaseState extends State { orgId = await getOrgId(); roleUser = await getRoleUser(); - if (token == null || userId == null) { print("Token or USerId missing"); return; } } + void _checkAuthAndLoadData() async { + final String? token = await getToken(); // Your async function to get token + + if (token == null || token.isEmpty) { + // Token doesn't exist → redirect to login + context.go( + "/", + ); // or use: router.go("/") if you're using `GoRouter` directly + return; + } + if (!mounted) return; + try { + WidgetsBinding.instance.addPostFrameCallback((_) { + loadInitialData(); + }); + } catch (e) { + print("service report : $e"); + } + } Future getUserId() async { final prefs = await SharedPreferences.getInstance(); @@ -152,18 +198,30 @@ class _AdvancePurchaseState extends State { return prefs.getString('auth_token'); } - Future handleSubmit() async { errorMessages.remove("from_date"); errorMessages.remove("to_date"); - + setState(() { + domesticData = []; + internationalData = []; + currentPage1 = 0; + itemsPerPage1 = 10; + currentPage2 = 0; + itemsPerPage2 = 10; + }); final fromDateText = textControllers["from_date"]?.text; final toDateText = textControllers["to_date"]?.text; - if (fromDateText == null || fromDateText.isEmpty || - toDateText == null || toDateText.isEmpty) { - errorMessages["from_date"] = "Required"; - errorMessages["to_date"] = "Required"; + if (fromDateText == null || + fromDateText.isEmpty || + toDateText == null || + toDateText.isEmpty) { + fromDateText == null || fromDateText.isEmpty + ? errorMessages["from_date"] = "Required" + : errorMessages.remove("from_date"); + toDateText == null || toDateText.isEmpty + ? errorMessages["to_date"] = "Required" + : errorMessages.remove("to_date"); setState(() {}); return; } @@ -179,34 +237,145 @@ class _AdvancePurchaseState extends State { setState(() {}); return; } + setState(() { + loaderFlag = true; + }); // Format for API request final formattedfromDate = DateFormat('yyyy-MM-dd').format(fromDate); final formattedtoDate = DateFormat('yyyy-MM-dd').format(toDate); // Fetch and update - final result = await apiService.CallReports( + + loaderFlag = true; + try { + final result = await apiService.CallReports( + 'advancePurchaseReport', + jsonEncode({ + "fromDate": '$formattedfromDate', + "toDate": '$formattedtoDate', + }), + ); + setState(() { + domesticData = List>.from( + result['status'] == 'success' ? result['data']['domestic'] ?? [] : [], + ); + // filteredDomestic = domesticData; + + + internationalData = List>.from( + result['status'] == 'success' + ? result['data']['international'] ?? [] + : [], + ); + loaderFlag = false; + }); + } catch (e) { + // handle error + setState(() { + loaderFlag = false; + domesticData = []; + internationalData = []; + }); + } + } + + Future handleDownload() async { + final dateFormat = DateFormat('dd-MM-yyyy'); + + if (textControllers["from_date"]!.text.isEmpty || + textControllers["to_date"]!.text.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: Colors.redAccent, + content: Text("Please choose a valid date range."), + behavior: SnackBarBehavior.floating, + ), + ); + return; + } + + final DateTime fromDate = dateFormat.parse( + textControllers["from_date"]!.text, + ); + final DateTime toDate = dateFormat.parse(textControllers["to_date"]!.text); + + final formattedFromDate = DateFormat('yyyy-MM-dd').format(fromDate); + final formattedToDate = DateFormat('yyyy-MM-dd').format(toDate); + + final name = + 'Advance Purchase - $selectedTabName Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})'; + final safeName = name.replaceAll(RegExp(r'[^\w\s-]'), ''); + final excelName = '$safeName'; + + final result = await apiService.reportExcelDownload( 'advancePurchaseReport', - formattedfromDate, - formattedtoDate, + jsonEncode({ + "fromDate": formattedFromDate, + "toDate": formattedToDate, + "export": selectedTabName, + }), + excelName, ); - setState(() { - domesticData = List>.from(result['data']['domestic'] ?? []); - internationData = List>.from(result['data']['international'] ?? []); - }); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: Colors.green, + content: Text(result as String), + behavior: SnackBarBehavior.floating, + ), + ); } + // void handleDomesticFilter(String query) { + // print(" so sad :( ** "); + // print("filtereddomesticData: $domesticData"); + // + // final lowerQuery = query.toLowerCase(); + // setState(() { + // filteredDomestic = + // domesticData.where((object) { + // return (object['plan_id']?.toLowerCase().contains(lowerQuery) ?? false) || + // (object['employee_code']?.toLowerCase().contains(lowerQuery) ?? false) || + // (object['so_number']?.toLowerCase().contains(lowerQuery) ?? false) || + // (object['functional_department']?.toLowerCase().contains(lowerQuery) ?? false) || + // (object['flight_trip_type']?.toLowerCase().contains(lowerQuery) ?? false) || + // (object['plan_trip_type']?.toLowerCase().contains(lowerQuery) ?? false) || + // (object['sector']?.toLowerCase().contains(lowerQuery)); + // }).toList(); + // currentPage1 = 0; + // }); + // print("filtereddomesticData: $filteredDomestic"); + // } + + // void handleInternationalFilter(String query) { + // final lowerQuery = query.toLowerCase(); + // setState(() { + // filteredInternational = + // internationalData.where((object) { + // return (object['plan_id']?.toLowerCase().contains(lowerQuery) ?? false) || + // (object['employee_code']?.toLowerCase().contains(lowerQuery) ?? false) || + // (object['so_number']?.toLowerCase().contains(lowerQuery) ?? false) || + // (object['functional_department']?.toLowerCase().contains(lowerQuery) ?? false) || + // (object['flight_trip_type']?.toLowerCase().contains(lowerQuery) ?? false) || + // (object['plan_trip_type']?.toLowerCase().contains(lowerQuery) ?? false) || + // (object['sector']?.toLowerCase().contains(lowerQuery)); + // }).toList(); + // currentPage1 = 0; + // }); + // print("filteredInternational: $filteredInternational"); + // } + @override // Widget build(BuildContext context) { // // TODO: implement build // throw UnimplementedError(); // } - Widget build(BuildContext context) { return ResponsiveBuilder( builder: (context, sizingInfo) { - bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop; + bool isDesktop = + sizingInfo.deviceScreenType == DeviceScreenType.desktop; return Scaffold( backgroundColor: Color(0xFFf5f5f5), @@ -214,21 +383,21 @@ class _AdvancePurchaseState extends State { 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), + 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), // const Expanded(child: Center(child: Text("User Page Content"))), - Expanded(child: buildAdvancePurchaseLayout(isDesktop)) + Expanded(child: buildAdvancePurchaseLayout(isDesktop)), ], ), ), @@ -238,20 +407,20 @@ class _AdvancePurchaseState extends State { } Widget buildAdvancePurchaseLayout(bool isDesktop) { - return Container( child: buildAdvancePurchaseFormLayout(isDesktop) ); + return Container(child: buildAdvancePurchaseFormLayout(isDesktop)); } Widget buildAdvancePurchaseFormLayout(bool isDesktop) { return Container( margin: isDesktop ? EdgeInsets.all(10.0) : null, - padding: const EdgeInsets.only(top: 15, bottom: 15, left: 20, right: 20), - height: isDesktop - ? MediaQuery.of(context).size.height * 0.98 - : MediaQuery.of(context).size.height, + padding: const EdgeInsets.only(top: 5, bottom: 5, left: 20, right: 20), + // color: Colors.brown, + height: + isDesktop + ? MediaQuery.of(context).size.height * 1 + : MediaQuery.of(context).size.height, decoration: BoxDecoration( - border: isDesktop - ? Border.all(width: 2, color: Colors.white) - : null, + border: isDesktop ? Border.all(width: 2, color: Colors.white) : null, color: isDesktop ? Colors.white : Color(0xFFFCFCFC), ), child: Column( @@ -278,11 +447,12 @@ class _AdvancePurchaseState extends State { borderRadius: BorderRadius.circular(8), side: BorderSide(color: Color(0xFF114D8B), width: 2), ), - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + padding: EdgeInsets.symmetric( + horizontal: 20, + vertical: 12, + ), ), - onPressed: () { - // Your Excel export logic here - }, + onPressed: handleDownload, child: Row( children: [ Text( @@ -293,42 +463,46 @@ class _AdvancePurchaseState extends State { ), ), SizedBox(width: 8), - Icon(Icons.file_present_outlined, size: 15, color: Colors.white), - ], - ), - ), - SizedBox(width: 10), - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFF114D8B), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide(color: Color(0xFF114D8B), width: 2), - ), - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), - ), - onPressed: () { - // Your PDF export logic here - }, - child: Row( - children: [ - Text( - "PDF", - style: GoogleFonts.poppins( - fontSize: isDesktop ? 13 : 11, - color: Colors.white, - ), + Icon( + Icons.file_present_outlined, + size: 15, + color: Colors.white, ), - SizedBox(width: 8), - Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), ], ), ), + // SizedBox(width: 10), + // ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: Color(0xFF114D8B), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8), + // side: BorderSide(color: Color(0xFF114D8B), width: 2), + // ), + // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + // ), + // onPressed: () { + // // Your PDF export logic here + // }, + // child: Row( + // children: [ + // Text( + // "PDF", + // style: GoogleFonts.poppins( + // fontSize: isDesktop ? 13 : 11, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 8), + // Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), + // ], + // ), + // ), ], ), ], ), - SizedBox(height: 15), + SizedBox(height: 5), // ------------------- Second Row ------------------- Row( @@ -336,8 +510,7 @@ class _AdvancePurchaseState extends State { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - "From Date *", + Text( "From Date *", style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, @@ -359,8 +532,9 @@ class _AdvancePurchaseState extends State { lastDate: DateTime(2100), ); if (pickedDate != null) { - textControllers["from_date"]?.text = - DateFormat('dd-MM-yyyy').format(pickedDate); + textControllers["from_date"]?.text = DateFormat( + 'dd-MM-yyyy', + ).format(pickedDate); } }, child: AbsorbPointer( @@ -375,9 +549,12 @@ class _AdvancePurchaseState extends State { fontSize: 12, color: Colors.grey, ), - floatingLabelBehavior: FloatingLabelBehavior.never, + floatingLabelBehavior: + FloatingLabelBehavior.never, border: InputBorder.none, - contentPadding: const EdgeInsets.symmetric(vertical: 16), + contentPadding: const EdgeInsets.symmetric( + vertical: 16, + ), suffixIcon: const Icon( Icons.calendar_today, size: 16, @@ -402,8 +579,7 @@ class _AdvancePurchaseState extends State { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - "To Date *", + Text( "To Date *", style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, @@ -418,10 +594,13 @@ class _AdvancePurchaseState extends State { height: 40, child: GestureDetector( onTap: () async { - final fromDateText = textControllers["from_date"]?.text; + final fromDateText = + textControllers["from_date"]?.text; DateTime? mintoDate; if (fromDateText != null && fromDateText.isNotEmpty) { - mintoDate = DateFormat('dd-MM-yyyy').parse(fromDateText); + mintoDate = DateFormat( + 'dd-MM-yyyy', + ).parse(fromDateText); } final pickedDate = await showDatePicker( @@ -432,8 +611,9 @@ class _AdvancePurchaseState extends State { ); if (pickedDate != null) { - textControllers["to_date"]?.text = - DateFormat('dd-MM-yyyy').format(pickedDate); + textControllers["to_date"]?.text = DateFormat( + 'dd-MM-yyyy', + ).format(pickedDate); } }, child: AbsorbPointer( @@ -444,10 +624,16 @@ class _AdvancePurchaseState extends State { style: const TextStyle(fontSize: 12), decoration: const InputDecoration( labelText: "Select Date", - labelStyle: TextStyle(fontSize: 12, color: Colors.grey), - floatingLabelBehavior: FloatingLabelBehavior.never, + labelStyle: TextStyle( + fontSize: 12, + color: Colors.grey, + ), + floatingLabelBehavior: + FloatingLabelBehavior.never, border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(vertical: 16), + contentPadding: EdgeInsets.symmetric( + vertical: 16, + ), suffixIcon: Icon( Icons.calendar_today, size: 16, @@ -466,52 +652,54 @@ class _AdvancePurchaseState extends State { style: const TextStyle(color: Colors.red, fontSize: 12), maxLines: 2, // Allow it to wrap onto two lines overflow: - TextOverflow.ellipsis, // Add ellipsis if it still overflows + TextOverflow + .ellipsis, // Add ellipsis if it still overflows ), ], ], ), if (isDesktop) Spacer() else SizedBox(height: 8), - SizedBox( - child: ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFF114D8B), - foregroundColor: Colors.white, - disabledBackgroundColor: Color(0xFF114D8B), - disabledForegroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide(color: Color(0xFF114D8B), width: 2), + Padding( + padding: EdgeInsets.only(top: 10, left: 4), + child: SizedBox( + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Color(0xFF114D8B), + foregroundColor: Colors.white, + disabledBackgroundColor: Color(0xFF114D8B), + disabledForegroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide(color: Color(0xFF114D8B), width: 2), + ), + padding: EdgeInsets.symmetric( + horizontal: 20, + vertical: 12, + ), ), - padding: EdgeInsets.symmetric( - horizontal: 20, - vertical: 12, - ), - ), - onPressed: () {handleSubmit();}, - child: Row( - mainAxisSize: - MainAxisSize.min, // Ensures content fits nicely - children: [ - Text( - "Search", - style: GoogleFonts.poppins( - fontSize: isDesktop ? 13 : 11, + onPressed: () { + handleSubmit(); + }, + child: Row( + mainAxisSize: + MainAxisSize.min, // Ensures content fits nicely + children: [ + Text( + "Search", + style: GoogleFonts.poppins( + fontSize: isDesktop ? 13 : 11, + ), ), - ), - SizedBox(width: 8), // spacing between icon and text - Icon( - Icons.search, - size: 15, - color: Colors.white, - ), - ], + SizedBox(width: 8), // spacing between icon and text + Icon(Icons.search, size: 15, color: Colors.white), + ], + ), ), ), ), ], ), - SizedBox(height: 15), + SizedBox(height: 5), // ------------------- Third Row ------------------- DefaultTabController( @@ -519,148 +707,839 @@ class _AdvancePurchaseState extends State { child: Column( children: [ TabBar( + controller: _tabController, labelColor: Colors.black, unselectedLabelColor: Colors.grey, indicatorColor: Color(0xFF114D8B), - tabs: [ - Tab(text: "Domestic"), - Tab(text: "International"), - ], + tabs: [Tab(text: "Domestic"), Tab(text: "International")], ), - SizedBox(height: 10), + SizedBox(height: 5), Container( - height: 200, // Or use Expanded for flexible height + // color:Colors.grey, + height: MediaQuery.of(context).size.height * 0.6, + // height: 200, // Or use Expanded for flexible height child: TabBarView( + controller: _tabController, children: [ - // Domestic Tab - domesticData.isEmpty + loaderFlag + ? Center(child: CircularProgressIndicator()) + : domesticData.isEmpty ? Center( - child: Padding( - padding: EdgeInsets.all(16), - child: Text( - "No data found", - style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w500), - ), - ), - ) - : Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), - child: Text( - "Domestic Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", - style: GoogleFonts.poppins(fontSize: 13, fontWeight: FontWeight.w500, color: Colors.grey[700]), - ), - ), - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: DataTable( - dividerThickness: 0.5, - columnSpacing: isDesktop ? 24.0 : 16.0, - border: TableBorder( - horizontalInside: BorderSide( - width: 0.5, - color: Colors.grey.shade200, - ), + child: Padding( + padding: EdgeInsets.all(16), + child: Text( + "No data found", + style: GoogleFonts.poppins( + fontSize: 14, + fontWeight: FontWeight.w500, ), - columns: [ - DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - ], - rows: domesticData.map((entry) { - return DataRow(cells: [ - DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), - ]); - }).toList(), ), ), + ) + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, + vertical: 8, + ), + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + /// Title on the left + Expanded( + child: Text( + "Domestic Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", + style: GoogleFonts.poppins( + fontSize: 13, + fontWeight: FontWeight.w500, + color: Colors.grey[700], + ), + overflow: + TextOverflow + .ellipsis, // Ensures title doesn't overflow + ), + ), + // SizedBox(width: 16), + // Container( + // width: MediaQuery.of(context).size.width * 0.2, + // height: 40, + // child: TextField( + // controller: searchController, + // onChanged: handleDomesticFilter, + // decoration: InputDecoration( + // hintText: "Search ...", + // hintStyle: TextStyle( + // fontSize: 12, + // color: Color(0xFF9E9DBD), + // ), + // prefixIcon: Icon( + // Icons.search, + // color: Color(0xFF9E9DBD), + // size: 18, + // ), + // border: OutlineInputBorder( + // borderRadius: BorderRadius.circular(12), + // ), + // enabledBorder: OutlineInputBorder( + // borderRadius: BorderRadius.circular(12), + // borderSide: BorderSide( + // color: Colors.grey.shade200, + // width: 0.5, + // ), + // ), + // focusedBorder: OutlineInputBorder( + // borderRadius: BorderRadius.circular(12), + // borderSide: BorderSide( + // color: Colors.grey.shade300, + // width: 1, + // ), + // ), + // ), + // style: GoogleFonts.poppins(fontSize: 12), + // ), + // ), + // /// Buttons on the right + // Row( + // children: [ + // ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: Color(0xFF114D8B), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8), + // side: BorderSide(color: Color(0xFF114D8B), width: 2), + // ), + // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + // ), + // onPressed: handleDownload, + // child: Row( + // children: [ + // Text( + // "Excel", + // style: GoogleFonts.poppins( + // fontSize: isDesktop ? 13 : 11, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 8), + // Icon(Icons.file_present_outlined, size: 15, color: Colors.white), + // ], + // ), + // ), + // SizedBox(width: 10), + // ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: Color(0xFF114D8B), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8), + // side: BorderSide(color: Color(0xFF114D8B), width: 2), + // ), + // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + // ), + // onPressed: handleDownload, + // child: Row( + // children: [ + // Text( + // "PDF", + // style: GoogleFonts.poppins( + // fontSize: isDesktop ? 13 : 11, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 8), + // Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), + // ], + // ), + // ), + // ], + // ), + ], + ), + ), + + /* For pagination for list ... */ + // Expanded( + // child: SingleChildScrollView( + // scrollDirection: Axis.horizontal, + // child: SingleChildScrollView( + // scrollDirection: Axis.vertical, + // child: DataTable( + // dividerThickness: 0.5, + // columnSpacing: isDesktop ? 30.0 : 24.0, + // border: TableBorder( + // horizontalInside: BorderSide( + // width: 0.5, + // color: Colors.grey.shade200, + // ), + // ), + // columns: [ + // DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // ], + // rows: domesticData.map((entry) { + // return DataRow(cells: [ + // DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), + // ]); + // }).toList(), + // ), + // ), + // ), + // ), + // -------- Table with Pagination -------- + Expanded( + child: LayoutBuilder( + builder: (context, constraints) { + final double minWidth = + isDesktop ? constraints.maxWidth : 1300; + + + // List> newDomesticData = + // filteredDomestic.isNotEmpty ? filteredDomestic : domesticData; + + + // Pagination logic + List> + paginatedDomestic = + domesticData + .skip(currentPage1 * itemsPerPage1) + .take(itemsPerPage1) + .toList(); + + return Column( + children: [ + Expanded( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: ConstrainedBox( + constraints: BoxConstraints( + minWidth: minWidth, + ), + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: DataTable( + dividerThickness: 0.5, + columnSpacing: + isDesktop ? 30.0 : 24.0, + border: TableBorder( + horizontalInside: + BorderSide( + width: 0.5, + color: + Colors + .grey + .shade200, + ), + ), + columns: [ + DataColumn( + label: Text( + 'Plan Id', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Employee Code', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'SO Number', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Department', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Flight Trip Type', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Plan Trip Type', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Sector', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + ], + rows: + paginatedDomestic.map(( + entry, + ) { + return DataRow( + cells: [ + DataCell( + Text( + '${entry['plan_id']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['employee_code']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['so_number']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['functional_department']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['flight_trip_type']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['plan_trip_type']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['sector']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + ], + ); + }).toList(), + ), + ), + ), + ), + ), + + // Pagination controls + PaginationControls( + currentPage: currentPage1, + itemsPerPage: itemsPerPage1, + totalItems: domesticData.length, + activeColor: layoutColor, + onPageChanged: (page) { + setState(() { + currentPage1 = page; + }); + }, + onItemsPerPageChanged: (items) { + setState(() { + itemsPerPage1 = items; + currentPage1 = 0; + }); + }, + ), + ], + ); + }, + ), + ), + ], ), - ], - ), // International Tab - internationData.isEmpty + internationalData.isEmpty ? Center( - child: Padding( - padding: EdgeInsets.all(16), - child: Text( - "No data found", - style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w500), - ), - ), - ) - : Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), - child: Text( - "International Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", - style: GoogleFonts.poppins(fontSize: 13, fontWeight: FontWeight.w500, color: Colors.grey[700]), - ), - ), - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: DataTable( - dividerThickness: 0.5, - columnSpacing: isDesktop ? 24.0 : 16.0, - border: TableBorder( - horizontalInside: BorderSide( - width: 0.5, - color: Colors.grey.shade200, - ), + child: Padding( + padding: EdgeInsets.all(16), + child: Text( + "No data found", + style: GoogleFonts.poppins( + fontSize: 14, + fontWeight: FontWeight.w500, ), - columns: [ - DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - ], - rows: internationData.map((entry) { - return DataRow(cells: [ - DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), - ]); - }).toList(), ), ), + ) + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Padding( + // padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), + // child: Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // crossAxisAlignment: CrossAxisAlignment.center, + // children: [ + // /// Title on the left + // Expanded( + // child: Text( + // "International Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", + // style: GoogleFonts.poppins( + // fontSize: 13, + // fontWeight: FontWeight.w500, + // color: Colors.grey[700], + // ), + // overflow: TextOverflow.ellipsis, // Ensures title doesn't overflow + // ), + // ), + // SizedBox(width: 16), + // /// Buttons on the right + // Row( + // children: [ + // ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: Color(0xFF114D8B), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8), + // side: BorderSide(color: Color(0xFF114D8B), width: 2), + // ), + // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + // ), + // onPressed: () { + // // Excel export logic + // }, + // child: Row( + // children: [ + // Text( + // "Excel", + // style: GoogleFonts.poppins( + // fontSize: isDesktop ? 13 : 11, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 8), + // Icon(Icons.file_present_outlined, size: 15, color: Colors.white), + // ], + // ), + // ), + // SizedBox(width: 10), + // ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: Color(0xFF114D8B), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8), + // side: BorderSide(color: Color(0xFF114D8B), width: 2), + // ), + // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + // ), + // onPressed: () { + // // PDF export logic + // }, + // child: Row( + // children: [ + // Text( + // "PDF", + // style: GoogleFonts.poppins( + // fontSize: isDesktop ? 13 : 11, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 8), + // Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), + // ], + // ), + // ), + // ], + // ), + // ], + // ), + // ), + // Expanded( + // child: SingleChildScrollView( + // scrollDirection: Axis.horizontal, + // child: SingleChildScrollView( + // scrollDirection: Axis.vertical, + // child: DataTable( + // dividerThickness: 0.5, + // columnSpacing: isDesktop ? 24.0 : 16.0, + // border: TableBorder( + // horizontalInside: BorderSide( + // width: 0.5, + // color: Colors.grey.shade200, + // ), + // ), + // columns: [ + // DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // ], + // rows: internationalData.map((entry) { + // return DataRow(cells: [ + // DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), + // ]); + // }).toList(), + // ), + // ), + // ), + // ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, + vertical: 8, + ), + child: Text( + "International Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", + style: GoogleFonts.poppins( + fontSize: 13, + fontWeight: FontWeight.w500, + color: Colors.grey[700], + ), + ), + ), + Container( + height: + isDesktop + ? MediaQuery.of(context).size.height * + 0.51 + : 200, + // color:Colors.amberAccent, + child: LayoutBuilder( + builder: (context, constraints) { + final double minWidth = + isDesktop ? constraints.maxWidth : 1300; + + // Pagination logic + List> + paginatedInternational = + internationalData + .skip(currentPage2 * itemsPerPage2) + .take(itemsPerPage2) + .toList(); + + return Column( + children: [ + Expanded( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: ConstrainedBox( + constraints: BoxConstraints( + minWidth: minWidth, + ), + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: DataTable( + dividerThickness: 0.5, + columnSpacing: + isDesktop ? 30.0 : 24.0, + border: TableBorder( + horizontalInside: + BorderSide( + width: 0.5, + color: + Colors + .grey + .shade200, + ), + ), + columns: [ + DataColumn( + label: Text( + 'Plan Id', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Employee Code', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'SO Number', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Department', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Flight Trip Type', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Plan Trip Type', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Sector', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + ], + rows: + paginatedInternational.map(( + entry, + ) { + return DataRow( + cells: [ + DataCell( + Text( + '${entry['plan_id']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['employee_code']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['so_number']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['functional_department']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['flight_trip_type']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['plan_trip_type']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['sector']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + ], + ); + }).toList(), + ), + ), + ), + ), + ), + + // Pagination controls + PaginationControls( + currentPage: currentPage2, + itemsPerPage: itemsPerPage2, + totalItems: internationalData.length, + activeColor: layoutColor, + onPageChanged: (page) { + setState(() { + currentPage2 = page; + }); + }, + onItemsPerPageChanged: (items) { + setState(() { + itemsPerPage2 = items; + currentPage2 = 0; + }); + }, + ), + ], + ); + }, + ), + ), + ], ), - ], - ), ], ), ), ], ), ), - SizedBox(height: 15), - + // SizedBox(height: 15), ], ), ); } - } - diff --git a/lib/Screens/reports/guestHouse.dart b/lib/Screens/reports/guestHouse.dart index be55a2a..c8dd587 100644 --- a/lib/Screens/reports/guestHouse.dart +++ b/lib/Screens/reports/guestHouse.dart @@ -1,5 +1,7 @@ import 'dart:convert'; import 'dart:core'; +import 'dart:typed_data'; + import 'package:go_router/go_router.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; @@ -8,12 +10,13 @@ import 'package:frontend/config/apiUrl.dart'; import 'package:intl/intl.dart'; import 'package:responsive_builder/responsive_builder.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:universal_html/html.dart' as html; import '../../routes/custom_appBar.dart'; import '../../routes/custom_drawer.dart'; -import '../../routes/mainLayout.dart'; import '../../services/apiService.dart'; import '../../utils/auth_utils.dart'; +import '../../utils/pagination.dart'; import '../../widgets/custom_text_field.dart'; class GuestHouse extends StatefulWidget { @@ -23,7 +26,8 @@ class GuestHouse extends StatefulWidget { _GuestHouseState createState() => _GuestHouseState(); } -class _GuestHouseState extends State { +class _GuestHouseState extends State + with SingleTickerProviderStateMixin { final ApiService apiService = ApiService(); String? userId; @@ -34,20 +38,29 @@ class _GuestHouseState extends State { Color? layoutColor; Color? bodyColor; + int currentPage1 = 0; + int itemsPerPage1 = 10; + int currentPage2 = 0; + int itemsPerPage2 = 10; + late TabController _tabController; + String selectedTabName = 'domestic'; Map focusNodes = {}; Map focusStates = {}; Map textControllers = {}; Map errorMessages = {}; // Map GuestHouseReport = {}; List> domesticData = []; - List> internationData = []; + List> internationalData = []; // Map domesticData = {}; - // Map internationData = {}; + // Map internationalData = {}; + + bool loaderFlag = false; @override void initState() { super.initState(); - + loadInitialData(); + _checkAuthAndLoadData(); if (!textControllers.containsKey("from_date")) { textControllers["from_date"] = TextEditingController(); } @@ -67,7 +80,17 @@ class _GuestHouseState extends State { focusStates["from_date"] = false; } + _tabController = TabController(length: 2, vsync: this); + _tabController.addListener(() { + if (_tabController.indexIsChanging == false) { + // Only fire when tab change is complete + setState(() { + selectedTabName = getTabName(_tabController.index); + }); + print(" :) :X Selected Tab: ${getTabName(_tabController.index)}"); + } + }); // Add focus listeners focusNodes.forEach((key, focusNode) { @@ -81,6 +104,19 @@ class _GuestHouseState extends State { getToken(); // fetchGuestHouseReport(); } + + String getTabName(int index) { + switch (index) { + case 0: + return "domestic"; + case 1: + return "international"; + default: + // return "Unknown"; + return "domestic"; + } + } + void _addFocusListener(FocusNode node, Function(bool) updateState) { node.addListener(() { setState(() { @@ -94,13 +130,36 @@ class _GuestHouseState extends State { String? bodyStringColor = await getBodyColor(); setState(() { - layoutColor = layoutString != null ? Color(int.parse(layoutString)) - : Colors.redAccent; + layoutColor = + layoutString != null + ? Color(int.parse(layoutString)) + : Colors.redAccent; - bodyColor = bodyStringColor != null ? Color(int.parse(bodyStringColor)) - : Colors.white; + bodyColor = + bodyStringColor != null + ? Color(int.parse(bodyStringColor)) + : Colors.white; }); + } + void _checkAuthAndLoadData() async { + final String? token = await getToken(); // Your async function to get token + + if (token == null || token.isEmpty) { + // Token doesn't exist → redirect to login + context.go( + "/", + ); // or use: router.go("/") if you're using `GoRouter` directly + return; + } + if (!mounted) return; + try { + WidgetsBinding.instance.addPostFrameCallback((_) { + loadInitialData(); + }); + } catch (e) { + print("service report : $e"); + } } Future initializeData() async { @@ -109,14 +168,12 @@ class _GuestHouseState extends State { orgId = await getOrgId(); roleUser = await getRoleUser(); - if (token == null || userId == null) { print("Token or USerId missing"); return; } } - Future getUserId() async { final prefs = await SharedPreferences.getInstance(); final String? userDataString = prefs.getString('user_data'); @@ -152,18 +209,30 @@ class _GuestHouseState extends State { return prefs.getString('auth_token'); } - Future handleSubmit() async { errorMessages.remove("from_date"); errorMessages.remove("to_date"); - + setState(() { + domesticData = []; + internationalData = []; + currentPage1 = 0; + itemsPerPage1 = 10; + currentPage2 = 0; + itemsPerPage2 = 10; + }); final fromDateText = textControllers["from_date"]?.text; final toDateText = textControllers["to_date"]?.text; - if (fromDateText == null || fromDateText.isEmpty || - toDateText == null || toDateText.isEmpty) { - errorMessages["from_date"] = "Required"; - errorMessages["to_date"] = "Required"; + if (fromDateText == null || + fromDateText.isEmpty || + toDateText == null || + toDateText.isEmpty) { + fromDateText == null || fromDateText.isEmpty + ? errorMessages["from_date"] = "Required" + : errorMessages.remove("from_date"); + toDateText == null || toDateText.isEmpty + ? errorMessages["to_date"] = "Required" + : errorMessages.remove("to_date"); setState(() {}); return; } @@ -179,22 +248,92 @@ class _GuestHouseState extends State { setState(() {}); return; } + setState(() { + loaderFlag = true; + }); // Format for API request final formattedfromDate = DateFormat('yyyy-MM-dd').format(fromDate); final formattedtoDate = DateFormat('yyyy-MM-dd').format(toDate); // Fetch and update - final result = await apiService.CallReports( + + loaderFlag = true; + try { + final result = await apiService.CallReports( + 'guestHouseReport', + jsonEncode({ + "fromDate": '$formattedfromDate', + "toDate": '$formattedtoDate', + }), + ); + setState(() { + domesticData = List>.from( + result['status'] == 'success' ? result['data']['domestic'] ?? [] : [], + ); + + internationalData = List>.from( + result['status'] == 'success' + ? result['data']['international'] ?? [] + : [], + ); + loaderFlag = false; + }); + } catch (e) { + // handle error + setState(() { + loaderFlag = false; + domesticData = []; + internationalData = []; + }); + } + } + + Future handleDownload() async { + final dateFormat = DateFormat('dd-MM-yyyy'); + + if (textControllers["from_date"]!.text.isEmpty || + textControllers["to_date"]!.text.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: Colors.redAccent, + content: Text("Please choose a valid date range."), + behavior: SnackBarBehavior.floating, + ), + ); + return; + } + + final DateTime fromDate = dateFormat.parse( + textControllers["from_date"]!.text, + ); + final DateTime toDate = dateFormat.parse(textControllers["to_date"]!.text); + + final formattedFromDate = DateFormat('yyyy-MM-dd').format(fromDate); + final formattedToDate = DateFormat('yyyy-MM-dd').format(toDate); + + final name = + 'Guest House - $selectedTabName Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})'; + final safeName = name.replaceAll(RegExp(r'[^\w\s-]'), ''); + final excelName = '$safeName'; + + final result = await apiService.reportExcelDownload( 'guestHouseReport', - formattedfromDate, - formattedtoDate, + jsonEncode({ + "fromDate": formattedFromDate, + "toDate": formattedToDate, + "export": selectedTabName, + }), + excelName, ); - setState(() { - domesticData = List>.from(result['data']['domestic'] ?? []); - internationData = List>.from(result['data']['international'] ?? []); - }); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: Colors.green, + content: Text(result as String), + behavior: SnackBarBehavior.floating, + ), + ); } @override @@ -202,11 +341,11 @@ class _GuestHouseState extends State { // // TODO: implement build // throw UnimplementedError(); // } - Widget build(BuildContext context) { return ResponsiveBuilder( builder: (context, sizingInfo) { - bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop; + bool isDesktop = + sizingInfo.deviceScreenType == DeviceScreenType.desktop; return Scaffold( backgroundColor: Color(0xFFf5f5f5), @@ -214,21 +353,21 @@ class _GuestHouseState extends State { 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), + 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), // const Expanded(child: Center(child: Text("User Page Content"))), - Expanded(child: buildGuestHouseLayout(isDesktop)) + Expanded(child: buildGuestHouseLayout(isDesktop)), ], ), ), @@ -238,20 +377,20 @@ class _GuestHouseState extends State { } Widget buildGuestHouseLayout(bool isDesktop) { - return Container( child: buildGuestHouseFormLayout(isDesktop) ); + return Container(child: buildGuestHouseFormLayout(isDesktop)); } Widget buildGuestHouseFormLayout(bool isDesktop) { return Container( margin: isDesktop ? EdgeInsets.all(10.0) : null, - padding: const EdgeInsets.only(top: 15, bottom: 15, left: 20, right: 20), - height: isDesktop - ? MediaQuery.of(context).size.height * 0.98 - : MediaQuery.of(context).size.height, + padding: const EdgeInsets.only(top: 5, bottom: 5, left: 20, right: 20), + // color: Colors.brown, + height: + isDesktop + ? MediaQuery.of(context).size.height * 1 + : MediaQuery.of(context).size.height, decoration: BoxDecoration( - border: isDesktop - ? Border.all(width: 2, color: Colors.white) - : null, + border: isDesktop ? Border.all(width: 2, color: Colors.white) : null, color: isDesktop ? Colors.white : Color(0xFFFCFCFC), ), child: Column( @@ -278,11 +417,12 @@ class _GuestHouseState extends State { borderRadius: BorderRadius.circular(8), side: BorderSide(color: Color(0xFF114D8B), width: 2), ), - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + padding: EdgeInsets.symmetric( + horizontal: 20, + vertical: 12, + ), ), - onPressed: () { - // Your Excel export logic here - }, + onPressed: handleDownload, child: Row( children: [ Text( @@ -293,34 +433,11 @@ class _GuestHouseState extends State { ), ), SizedBox(width: 8), - Icon(Icons.file_present_outlined, size: 15, color: Colors.white), - ], - ), - ), - SizedBox(width: 10), - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFF114D8B), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide(color: Color(0xFF114D8B), width: 2), - ), - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), - ), - onPressed: () { - // Your PDF export logic here - }, - child: Row( - children: [ - Text( - "PDF", - style: GoogleFonts.poppins( - fontSize: isDesktop ? 13 : 11, - color: Colors.white, - ), + Icon( + Icons.file_present_outlined, + size: 15, + color: Colors.white, ), - SizedBox(width: 8), - Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), ], ), ), @@ -328,7 +445,7 @@ class _GuestHouseState extends State { ), ], ), - SizedBox(height: 15), + SizedBox(height: 5), // ------------------- Second Row ------------------- Row( @@ -359,8 +476,9 @@ class _GuestHouseState extends State { lastDate: DateTime(2100), ); if (pickedDate != null) { - textControllers["from_date"]?.text = - DateFormat('dd-MM-yyyy').format(pickedDate); + textControllers["from_date"]?.text = DateFormat( + 'dd-MM-yyyy', + ).format(pickedDate); } }, child: AbsorbPointer( @@ -375,9 +493,12 @@ class _GuestHouseState extends State { fontSize: 12, color: Colors.grey, ), - floatingLabelBehavior: FloatingLabelBehavior.never, + floatingLabelBehavior: + FloatingLabelBehavior.never, border: InputBorder.none, - contentPadding: const EdgeInsets.symmetric(vertical: 16), + contentPadding: const EdgeInsets.symmetric( + vertical: 16, + ), suffixIcon: const Icon( Icons.calendar_today, size: 16, @@ -418,10 +539,13 @@ class _GuestHouseState extends State { height: 40, child: GestureDetector( onTap: () async { - final fromDateText = textControllers["from_date"]?.text; + final fromDateText = + textControllers["from_date"]?.text; DateTime? mintoDate; if (fromDateText != null && fromDateText.isNotEmpty) { - mintoDate = DateFormat('dd-MM-yyyy').parse(fromDateText); + mintoDate = DateFormat( + 'dd-MM-yyyy', + ).parse(fromDateText); } final pickedDate = await showDatePicker( @@ -432,8 +556,9 @@ class _GuestHouseState extends State { ); if (pickedDate != null) { - textControllers["to_date"]?.text = - DateFormat('dd-MM-yyyy').format(pickedDate); + textControllers["to_date"]?.text = DateFormat( + 'dd-MM-yyyy', + ).format(pickedDate); } }, child: AbsorbPointer( @@ -444,10 +569,16 @@ class _GuestHouseState extends State { style: const TextStyle(fontSize: 12), decoration: const InputDecoration( labelText: "Select Date", - labelStyle: TextStyle(fontSize: 12, color: Colors.grey), - floatingLabelBehavior: FloatingLabelBehavior.never, + labelStyle: TextStyle( + fontSize: 12, + color: Colors.grey, + ), + floatingLabelBehavior: + FloatingLabelBehavior.never, border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(vertical: 16), + contentPadding: EdgeInsets.symmetric( + vertical: 16, + ), suffixIcon: Icon( Icons.calendar_today, size: 16, @@ -466,52 +597,54 @@ class _GuestHouseState extends State { style: const TextStyle(color: Colors.red, fontSize: 12), maxLines: 2, // Allow it to wrap onto two lines overflow: - TextOverflow.ellipsis, // Add ellipsis if it still overflows + TextOverflow + .ellipsis, // Add ellipsis if it still overflows ), ], ], ), if (isDesktop) Spacer() else SizedBox(height: 8), - SizedBox( - child: ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFF114D8B), - foregroundColor: Colors.white, - disabledBackgroundColor: Color(0xFF114D8B), - disabledForegroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide(color: Color(0xFF114D8B), width: 2), + Padding( + padding: EdgeInsets.only(top: 10, left: 4), + child: SizedBox( + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Color(0xFF114D8B), + foregroundColor: Colors.white, + disabledBackgroundColor: Color(0xFF114D8B), + disabledForegroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide(color: Color(0xFF114D8B), width: 2), + ), + padding: EdgeInsets.symmetric( + horizontal: 20, + vertical: 12, + ), ), - padding: EdgeInsets.symmetric( - horizontal: 20, - vertical: 12, - ), - ), - onPressed: () {handleSubmit();}, - child: Row( - mainAxisSize: - MainAxisSize.min, // Ensures content fits nicely - children: [ - Text( - "Search", - style: GoogleFonts.poppins( - fontSize: isDesktop ? 13 : 11, + onPressed: () { + handleSubmit(); + }, + child: Row( + mainAxisSize: + MainAxisSize.min, // Ensures content fits nicely + children: [ + Text( + "Search", + style: GoogleFonts.poppins( + fontSize: isDesktop ? 13 : 11, + ), ), - ), - SizedBox(width: 8), // spacing between icon and text - Icon( - Icons.search, - size: 15, - color: Colors.white, - ), - ], + SizedBox(width: 8), // spacing between icon and text + Icon(Icons.search, size: 15, color: Colors.white), + ], + ), ), ), ), ], ), - SizedBox(height: 15), + SizedBox(height: 5), // ------------------- Third Row ------------------- DefaultTabController( @@ -519,148 +652,910 @@ class _GuestHouseState extends State { child: Column( children: [ TabBar( + controller: _tabController, labelColor: Colors.black, unselectedLabelColor: Colors.grey, indicatorColor: Color(0xFF114D8B), - tabs: [ - Tab(text: "Domestic"), - Tab(text: "International"), - ], + tabs: [Tab(text: "Domestic"), Tab(text: "International")], ), - SizedBox(height: 10), + SizedBox(height: 5), Container( - height: 200, // Or use Expanded for flexible height + // color:Colors.grey, + height: MediaQuery.of(context).size.height * 0.6, + // height: 200, // Or use Expanded for flexible height child: TabBarView( + controller: _tabController, children: [ - // Domestic Tab - domesticData.isEmpty + loaderFlag + ? Center(child: CircularProgressIndicator()) + : domesticData.isEmpty ? Center( - child: Padding( - padding: EdgeInsets.all(16), - child: Text( - "No data found", - style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w500), - ), - ), - ) - : Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), - child: Text( - "Domestic Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", - style: GoogleFonts.poppins(fontSize: 13, fontWeight: FontWeight.w500, color: Colors.grey[700]), - ), - ), - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: DataTable( - dividerThickness: 0.5, - columnSpacing: isDesktop ? 24.0 : 16.0, - border: TableBorder( - horizontalInside: BorderSide( - width: 0.5, - color: Colors.grey.shade200, - ), + child: Padding( + padding: EdgeInsets.all(16), + child: Text( + "No data found", + style: GoogleFonts.poppins( + fontSize: 14, + fontWeight: FontWeight.w500, ), - columns: [ - DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - ], - rows: domesticData.map((entry) { - return DataRow(cells: [ - DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), - ]); - }).toList(), ), ), + ) + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, + vertical: 8, + ), + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + /// Title on the left + Expanded( + child: Text( + "Domestic Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", + style: GoogleFonts.poppins( + fontSize: 13, + fontWeight: FontWeight.w500, + color: Colors.grey[700], + ), + overflow: + TextOverflow + .ellipsis, // Ensures title doesn't overflow + ), + ), + // SizedBox(width: 16), + // /// Buttons on the right + // Row( + // children: [ + // ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: Color(0xFF114D8B), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8), + // side: BorderSide(color: Color(0xFF114D8B), width: 2), + // ), + // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + // ), + // onPressed: handleDownload, + // child: Row( + // children: [ + // Text( + // "Excel", + // style: GoogleFonts.poppins( + // fontSize: isDesktop ? 13 : 11, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 8), + // Icon(Icons.file_present_outlined, size: 15, color: Colors.white), + // ], + // ), + // ), + // SizedBox(width: 10), + // ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: Color(0xFF114D8B), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8), + // side: BorderSide(color: Color(0xFF114D8B), width: 2), + // ), + // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + // ), + // onPressed: handleDownload, + // child: Row( + // children: [ + // Text( + // "PDF", + // style: GoogleFonts.poppins( + // fontSize: isDesktop ? 13 : 11, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 8), + // Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), + // ], + // ), + // ), + // ], + // ), + ], + ), + ), + + /* For pagination for list ... */ + // Expanded( + // child: SingleChildScrollView( + // scrollDirection: Axis.horizontal, + // child: SingleChildScrollView( + // scrollDirection: Axis.vertical, + // child: DataTable( + // dividerThickness: 0.5, + // columnSpacing: isDesktop ? 30.0 : 24.0, + // border: TableBorder( + // horizontalInside: BorderSide( + // width: 0.5, + // color: Colors.grey.shade200, + // ), + // ), + // columns: [ + // DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // ], + // rows: domesticData.map((entry) { + // return DataRow(cells: [ + // DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), + // ]); + // }).toList(), + // ), + // ), + // ), + // ), + // -------- Table with Pagination -------- + Expanded( + child: LayoutBuilder( + builder: (context, constraints) { + final double minWidth = + isDesktop ? constraints.maxWidth : 1300; + + // Pagination logic + List> + paginatedDomestic = + domesticData + .skip(currentPage1 * itemsPerPage1) + .take(itemsPerPage1) + .toList(); + + return Column( + children: [ + Expanded( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: ConstrainedBox( + constraints: BoxConstraints( + minWidth: minWidth, + ), + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: DataTable( + dividerThickness: 0.5, + columnSpacing: + isDesktop ? 30.0 : 24.0, + border: TableBorder( + horizontalInside: + BorderSide( + width: 0.5, + color: + Colors + .grey + .shade200, + ), + ), + columns: [ + DataColumn( + label: Text( + 'Plan Id', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Employee Code', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'SO Number', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Department', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Flight Trip Type', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Plan Trip Type', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Sector', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Class', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Travel Date', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + ], + rows: + paginatedDomestic.map(( + entry, + ) { + final flightTravelDate = + DateFormat( + 'yyyy-MM-dd', + ).format( + DateTime.parse( + entry['flight_travel_date'], + ), + ); + return DataRow( + cells: [ + DataCell( + Text( + '${entry['plan_id']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['employee_code']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['so_number']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['functional_department']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['flight_trip_type']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['plan_trip_type']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['sector']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['flight_class']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + flightTravelDate, + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + ], + ); + }).toList(), + ), + ), + ), + ), + ), + + // Pagination controls + PaginationControls( + currentPage: currentPage1, + itemsPerPage: itemsPerPage1, + totalItems: domesticData.length, + activeColor: layoutColor, + onPageChanged: (page) { + setState(() { + currentPage1 = page; + }); + }, + onItemsPerPageChanged: (items) { + setState(() { + itemsPerPage1 = items; + currentPage1 = 0; + }); + }, + ), + ], + ); + }, + ), + ), + ], ), - ], - ), // International Tab - internationData.isEmpty + internationalData.isEmpty ? Center( - child: Padding( - padding: EdgeInsets.all(16), - child: Text( - "No data found", - style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w500), - ), - ), - ) - : Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), - child: Text( - "International Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", - style: GoogleFonts.poppins(fontSize: 13, fontWeight: FontWeight.w500, color: Colors.grey[700]), - ), - ), - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: DataTable( - dividerThickness: 0.5, - columnSpacing: isDesktop ? 24.0 : 16.0, - border: TableBorder( - horizontalInside: BorderSide( - width: 0.5, - color: Colors.grey.shade200, - ), + child: Padding( + padding: EdgeInsets.all(16), + child: Text( + "No data found", + style: GoogleFonts.poppins( + fontSize: 14, + fontWeight: FontWeight.w500, ), - columns: [ - DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - ], - rows: internationData.map((entry) { - return DataRow(cells: [ - DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), - ]); - }).toList(), ), ), + ) + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Padding( + // padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), + // child: Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // crossAxisAlignment: CrossAxisAlignment.center, + // children: [ + // /// Title on the left + // Expanded( + // child: Text( + // "International Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", + // style: GoogleFonts.poppins( + // fontSize: 13, + // fontWeight: FontWeight.w500, + // color: Colors.grey[700], + // ), + // overflow: TextOverflow.ellipsis, // Ensures title doesn't overflow + // ), + // ), + // SizedBox(width: 16), + // /// Buttons on the right + // Row( + // children: [ + // ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: Color(0xFF114D8B), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8), + // side: BorderSide(color: Color(0xFF114D8B), width: 2), + // ), + // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + // ), + // onPressed: () { + // // Excel export logic + // }, + // child: Row( + // children: [ + // Text( + // "Excel", + // style: GoogleFonts.poppins( + // fontSize: isDesktop ? 13 : 11, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 8), + // Icon(Icons.file_present_outlined, size: 15, color: Colors.white), + // ], + // ), + // ), + // SizedBox(width: 10), + // ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: Color(0xFF114D8B), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8), + // side: BorderSide(color: Color(0xFF114D8B), width: 2), + // ), + // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + // ), + // onPressed: () { + // // PDF export logic + // }, + // child: Row( + // children: [ + // Text( + // "PDF", + // style: GoogleFonts.poppins( + // fontSize: isDesktop ? 13 : 11, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 8), + // Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), + // ], + // ), + // ), + // ], + // ), + // ], + // ), + // ), + // Expanded( + // child: SingleChildScrollView( + // scrollDirection: Axis.horizontal, + // child: SingleChildScrollView( + // scrollDirection: Axis.vertical, + // child: DataTable( + // dividerThickness: 0.5, + // columnSpacing: isDesktop ? 24.0 : 16.0, + // border: TableBorder( + // horizontalInside: BorderSide( + // width: 0.5, + // color: Colors.grey.shade200, + // ), + // ), + // columns: [ + // DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // ], + // rows: internationalData.map((entry) { + // return DataRow(cells: [ + // DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), + // ]); + // }).toList(), + // ), + // ), + // ), + // ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, + vertical: 8, + ), + child: Text( + "International Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", + style: GoogleFonts.poppins( + fontSize: 13, + fontWeight: FontWeight.w500, + color: Colors.grey[700], + ), + ), + ), + Container( + height: + isDesktop + ? MediaQuery.of(context).size.height * + 0.51 + : 200, + // color:Colors.amberAccent, + child: LayoutBuilder( + builder: (context, constraints) { + final double minWidth = + isDesktop ? constraints.maxWidth : 1300; + + // Pagination logic + List> + paginatedInternational = + internationalData + .skip(currentPage2 * itemsPerPage2) + .take(itemsPerPage2) + .toList(); + + return Column( + children: [ + Expanded( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: ConstrainedBox( + constraints: BoxConstraints( + minWidth: minWidth, + ), + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: DataTable( + dividerThickness: 0.5, + columnSpacing: + isDesktop ? 30.0 : 24.0, + border: TableBorder( + horizontalInside: + BorderSide( + width: 0.5, + color: + Colors + .grey + .shade200, + ), + ), + columns: [ + // "plan_id": "17", + // "employee_code": "TS_004", + // "customer_name": "sangeetha E", + // "so_number": "12345", + // "functional_department": "HR", + // "flight_trip_type": "Roundtrip", + // "plan_trip_type": "international", + // "sector": "Rajiv Gandhi International (Hyderabad) - Canadian Rockies Intl (Cranbrook)", + // "flight_class": "Business", + // "flight_travel_date": "2025-06-11" + DataColumn( + label: Text( + 'Plan Id', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Employee Code', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'SO Number', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Department', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Flight Trip Type', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Plan Trip Type', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Sector', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Class', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Travel Date', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + ], + rows: + paginatedInternational.map(( + entry, + ) { + final flightTravelDate = + DateFormat( + 'yyyy-MM-dd', + ).format( + DateTime.parse( + entry['flight_travel_date'], + ), + ); + return DataRow( + cells: [ + DataCell( + Text( + '${entry['plan_id']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['employee_code']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['so_number']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['functional_department']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['flight_trip_type']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['plan_trip_type']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['sector']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['flight_class']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + flightTravelDate, + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + ], + ); + }).toList(), + ), + ), + ), + ), + ), + + // Pagination controls + PaginationControls( + currentPage: currentPage2, + itemsPerPage: itemsPerPage2, + totalItems: internationalData.length, + activeColor: layoutColor, + onPageChanged: (page) { + setState(() { + currentPage2 = page; + }); + }, + onItemsPerPageChanged: (items) { + setState(() { + itemsPerPage2 = items; + currentPage2 = 0; + }); + }, + ), + ], + ); + }, + ), + ), + ], ), - ], - ), ], ), ), ], ), ), - SizedBox(height: 15), - + // SizedBox(height: 15), ], ), ); } - } - diff --git a/lib/Screens/reports/misAir.dart b/lib/Screens/reports/misAir.dart index 516918a..9207bc3 100644 --- a/lib/Screens/reports/misAir.dart +++ b/lib/Screens/reports/misAir.dart @@ -1,5 +1,7 @@ import 'dart:convert'; import 'dart:core'; +import 'dart:typed_data'; + import 'package:go_router/go_router.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; @@ -8,24 +10,23 @@ import 'package:frontend/config/apiUrl.dart'; import 'package:intl/intl.dart'; import 'package:responsive_builder/responsive_builder.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:universal_html/html.dart' as html; import '../../routes/custom_appBar.dart'; import '../../routes/custom_drawer.dart'; -import '../../routes/mainLayout.dart'; import '../../services/apiService.dart'; import '../../utils/auth_utils.dart'; import '../../utils/pagination.dart'; import '../../widgets/custom_text_field.dart'; -class AdvancePurchase extends StatefulWidget { - const AdvancePurchase({super.key}); +class MISair extends StatefulWidget { + const MISair({super.key}); @override - _AdvancePurchaseState createState() => _AdvancePurchaseState(); + _MISairState createState() => _MISairState(); } -class _AdvancePurchaseState extends State - with SingleTickerProviderStateMixin { +class _MISairState extends State with SingleTickerProviderStateMixin { final ApiService apiService = ApiService(); String? userId; @@ -33,7 +34,6 @@ class _AdvancePurchaseState extends State String? roleUser; String? token; - Color? layoutColor; Color? bodyColor; @@ -42,12 +42,12 @@ class _AdvancePurchaseState extends State int currentPage2 = 0; int itemsPerPage2 = 10; late TabController _tabController; - final List tabNames = ['Domestic', 'International']; + String selectedTabName = 'domestic'; Map focusNodes = {}; Map focusStates = {}; Map textControllers = {}; Map errorMessages = {}; - // Map advancePurchaseReport = {}; + // Map MISairReport = {}; List> domesticData = []; List> internationalData = []; // Map domesticData = {}; @@ -59,6 +59,7 @@ class _AdvancePurchaseState extends State void initState() { super.initState(); loadInitialData(); + _checkAuthAndLoadData(); if (!textControllers.containsKey("from_date")) { textControllers["from_date"] = TextEditingController(); } @@ -83,6 +84,9 @@ class _AdvancePurchaseState extends State _tabController.addListener(() { if (_tabController.indexIsChanging == false) { // Only fire when tab change is complete + setState(() { + selectedTabName = getTabName(_tabController.index); + }); print(" :) :X Selected Tab: ${getTabName(_tabController.index)}"); } }); @@ -97,17 +101,18 @@ class _AdvancePurchaseState extends State }); getToken(); - // fetchAdvancePurchaseReport(); + // fetchMISairReport(); } String getTabName(int index) { switch (index) { case 0: - return "Domestic"; + return "domestic"; case 1: - return "International"; + return "international"; default: - return "Unknown"; + // return "Unknown"; + return "domestic"; } } @@ -123,15 +128,37 @@ class _AdvancePurchaseState extends State String? layoutString = await getLayoutColor(); String? bodyStringColor = await getBodyColor(); - setState(() { - layoutColor = layoutString != null ? Color(int.parse(layoutString)) - : Colors.redAccent; + layoutColor = + layoutString != null + ? Color(int.parse(layoutString)) + : Colors.redAccent; - bodyColor = bodyStringColor != null ? Color(int.parse(bodyStringColor)) - : Colors.white; + bodyColor = + bodyStringColor != null + ? Color(int.parse(bodyStringColor)) + : Colors.white; }); + } + void _checkAuthAndLoadData() async { + final String? token = await getToken(); // Your async function to get token + + if (token == null || token.isEmpty) { + // Token doesn't exist → redirect to login + context.go( + "/", + ); // or use: router.go("/") if you're using `GoRouter` directly + return; + } + if (!mounted) return; + try { + WidgetsBinding.instance.addPostFrameCallback((_) { + loadInitialData(); + }); + } catch (e) { + print("service report : $e"); + } } Future initializeData() async { @@ -140,14 +167,12 @@ class _AdvancePurchaseState extends State orgId = await getOrgId(); roleUser = await getRoleUser(); - if (token == null || userId == null) { print("Token or USerId missing"); return; } } - Future getUserId() async { final prefs = await SharedPreferences.getInstance(); final String? userDataString = prefs.getString('user_data'); @@ -183,21 +208,30 @@ class _AdvancePurchaseState extends State return prefs.getString('auth_token'); } - Future handleSubmit() async { errorMessages.remove("from_date"); errorMessages.remove("to_date"); setState(() { domesticData = []; internationalData = []; + currentPage1 = 0; + itemsPerPage1 = 10; + currentPage2 = 0; + itemsPerPage2 = 10; }); final fromDateText = textControllers["from_date"]?.text; final toDateText = textControllers["to_date"]?.text; - if (fromDateText == null || fromDateText.isEmpty || - toDateText == null || toDateText.isEmpty) { - errorMessages["from_date"] = "Required"; - errorMessages["to_date"] = "Required"; + if (fromDateText == null || + fromDateText.isEmpty || + toDateText == null || + toDateText.isEmpty) { + fromDateText == null || fromDateText.isEmpty + ? errorMessages["from_date"] = "Required" + : errorMessages.remove("from_date"); + toDateText == null || toDateText.isEmpty + ? errorMessages["to_date"] = "Required" + : errorMessages.remove("to_date"); setState(() {}); return; } @@ -213,7 +247,9 @@ class _AdvancePurchaseState extends State setState(() {}); return; } - setState(() { loaderFlag = true; }); + setState(() { + loaderFlag = true; + }); // Format for API request final formattedfromDate = DateFormat('yyyy-MM-dd').format(fromDate); @@ -224,13 +260,22 @@ class _AdvancePurchaseState extends State loaderFlag = true; try { final result = await apiService.CallReports( - 'advancePurchaseReport', - formattedfromDate, - formattedtoDate, + 'misAirReport', + jsonEncode({ + "fromDate": '$formattedfromDate', + "toDate": '$formattedtoDate', + }), ); setState(() { - domesticData = List>.from(result['data']['domestic'] ?? []); - internationalData = List>.from(result['data']['international'] ?? []); + domesticData = List>.from( + result['status'] == 'success' ? result['data']['domestic'] ?? [] : [], + ); + + internationalData = List>.from( + result['status'] == 'success' + ? result['data']['international'] ?? [] + : [], + ); loaderFlag = false; }); } catch (e) { @@ -243,16 +288,63 @@ class _AdvancePurchaseState extends State } } + Future handleDownload() async { + final dateFormat = DateFormat('dd-MM-yyyy'); + + if (textControllers["from_date"]!.text.isEmpty || + textControllers["to_date"]!.text.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: Colors.redAccent, + content: Text("Please choose a valid date range."), + behavior: SnackBarBehavior.floating, + ), + ); + return; + } + + final DateTime fromDate = dateFormat.parse( + textControllers["from_date"]!.text, + ); + final DateTime toDate = dateFormat.parse(textControllers["to_date"]!.text); + + final formattedFromDate = DateFormat('yyyy-MM-dd').format(fromDate); + final formattedToDate = DateFormat('yyyy-MM-dd').format(toDate); + + final name = + 'MIS Air - $selectedTabName Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})'; + final safeName = name.replaceAll(RegExp(r'[^\w\s-]'), ''); + final excelName = '$safeName'; + + final result = await apiService.reportExcelDownload( + 'misAirReport', + jsonEncode({ + "fromDate": formattedFromDate, + "toDate": formattedToDate, + "export": selectedTabName, + }), + excelName, + ); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: Colors.green, + content: Text(result as String), + behavior: SnackBarBehavior.floating, + ), + ); + } + @override // Widget build(BuildContext context) { // // TODO: implement build // throw UnimplementedError(); // } - Widget build(BuildContext context) { return ResponsiveBuilder( builder: (context, sizingInfo) { - bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop; + bool isDesktop = + sizingInfo.deviceScreenType == DeviceScreenType.desktop; return Scaffold( backgroundColor: Color(0xFFf5f5f5), @@ -260,21 +352,21 @@ class _AdvancePurchaseState extends State 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), + 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), // const Expanded(child: Center(child: Text("User Page Content"))), - Expanded(child: buildAdvancePurchaseLayout(isDesktop)) + Expanded(child: buildMISairLayout(isDesktop)), ], ), ), @@ -283,22 +375,21 @@ class _AdvancePurchaseState extends State ); } - Widget buildAdvancePurchaseLayout(bool isDesktop) { - return Container( child: buildAdvancePurchaseFormLayout(isDesktop) ); + Widget buildMISairLayout(bool isDesktop) { + return Container(child: buildMISairFormLayout(isDesktop)); } - Widget buildAdvancePurchaseFormLayout(bool isDesktop) { + Widget buildMISairFormLayout(bool isDesktop) { return Container( margin: isDesktop ? EdgeInsets.all(10.0) : null, padding: const EdgeInsets.only(top: 5, bottom: 5, left: 20, right: 20), // color: Colors.brown, - height: isDesktop - ? MediaQuery.of(context).size.height * 1 - : MediaQuery.of(context).size.height, + height: + isDesktop + ? MediaQuery.of(context).size.height * 1 + : MediaQuery.of(context).size.height, decoration: BoxDecoration( - border: isDesktop - ? Border.all(width: 2, color: Colors.white) - : null, + border: isDesktop ? Border.all(width: 2, color: Colors.white) : null, color: isDesktop ? Colors.white : Color(0xFFFCFCFC), ), child: Column( @@ -309,7 +400,7 @@ class _AdvancePurchaseState extends State mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - 'Advance Purchase', + 'MIS Air Report ', style: GoogleFonts.poppins( fontSize: isDesktop ? 16 : 14, fontWeight: FontWeight.w600, @@ -325,11 +416,12 @@ class _AdvancePurchaseState extends State borderRadius: BorderRadius.circular(8), side: BorderSide(color: Color(0xFF114D8B), width: 2), ), - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + padding: EdgeInsets.symmetric( + horizontal: 20, + vertical: 12, + ), ), - onPressed: () { - // Your Excel export logic here - }, + onPressed: handleDownload, child: Row( children: [ Text( @@ -340,37 +432,41 @@ class _AdvancePurchaseState extends State ), ), SizedBox(width: 8), - Icon(Icons.file_present_outlined, size: 15, color: Colors.white), - ], - ), - ), - SizedBox(width: 10), - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFF114D8B), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide(color: Color(0xFF114D8B), width: 2), - ), - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), - ), - onPressed: () { - // Your PDF export logic here - }, - child: Row( - children: [ - Text( - "PDF", - style: GoogleFonts.poppins( - fontSize: isDesktop ? 13 : 11, - color: Colors.white, - ), + Icon( + Icons.file_present_outlined, + size: 15, + color: Colors.white, ), - SizedBox(width: 8), - Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), ], ), ), + // SizedBox(width: 10), + // ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: Color(0xFF114D8B), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8), + // side: BorderSide(color: Color(0xFF114D8B), width: 2), + // ), + // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + // ), + // onPressed: () { + // // Your PDF export logic here + // }, + // child: Row( + // children: [ + // Text( + // "PDF", + // style: GoogleFonts.poppins( + // fontSize: isDesktop ? 13 : 11, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 8), + // Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), + // ], + // ), + // ), ], ), ], @@ -406,8 +502,9 @@ class _AdvancePurchaseState extends State lastDate: DateTime(2100), ); if (pickedDate != null) { - textControllers["from_date"]?.text = - DateFormat('dd-MM-yyyy').format(pickedDate); + textControllers["from_date"]?.text = DateFormat( + 'dd-MM-yyyy', + ).format(pickedDate); } }, child: AbsorbPointer( @@ -422,9 +519,12 @@ class _AdvancePurchaseState extends State fontSize: 12, color: Colors.grey, ), - floatingLabelBehavior: FloatingLabelBehavior.never, + floatingLabelBehavior: + FloatingLabelBehavior.never, border: InputBorder.none, - contentPadding: const EdgeInsets.symmetric(vertical: 16), + contentPadding: const EdgeInsets.symmetric( + vertical: 16, + ), suffixIcon: const Icon( Icons.calendar_today, size: 16, @@ -465,10 +565,13 @@ class _AdvancePurchaseState extends State height: 40, child: GestureDetector( onTap: () async { - final fromDateText = textControllers["from_date"]?.text; + final fromDateText = + textControllers["from_date"]?.text; DateTime? mintoDate; if (fromDateText != null && fromDateText.isNotEmpty) { - mintoDate = DateFormat('dd-MM-yyyy').parse(fromDateText); + mintoDate = DateFormat( + 'dd-MM-yyyy', + ).parse(fromDateText); } final pickedDate = await showDatePicker( @@ -479,8 +582,9 @@ class _AdvancePurchaseState extends State ); if (pickedDate != null) { - textControllers["to_date"]?.text = - DateFormat('dd-MM-yyyy').format(pickedDate); + textControllers["to_date"]?.text = DateFormat( + 'dd-MM-yyyy', + ).format(pickedDate); } }, child: AbsorbPointer( @@ -491,10 +595,16 @@ class _AdvancePurchaseState extends State style: const TextStyle(fontSize: 12), decoration: const InputDecoration( labelText: "Select Date", - labelStyle: TextStyle(fontSize: 12, color: Colors.grey), - floatingLabelBehavior: FloatingLabelBehavior.never, + labelStyle: TextStyle( + fontSize: 12, + color: Colors.grey, + ), + floatingLabelBehavior: + FloatingLabelBehavior.never, border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(vertical: 16), + contentPadding: EdgeInsets.symmetric( + vertical: 16, + ), suffixIcon: Icon( Icons.calendar_today, size: 16, @@ -513,46 +623,48 @@ class _AdvancePurchaseState extends State style: const TextStyle(color: Colors.red, fontSize: 12), maxLines: 2, // Allow it to wrap onto two lines overflow: - TextOverflow.ellipsis, // Add ellipsis if it still overflows + TextOverflow + .ellipsis, // Add ellipsis if it still overflows ), ], ], ), if (isDesktop) Spacer() else SizedBox(height: 8), - SizedBox( - child: ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFF114D8B), - foregroundColor: Colors.white, - disabledBackgroundColor: Color(0xFF114D8B), - disabledForegroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide(color: Color(0xFF114D8B), width: 2), + Padding( + padding: EdgeInsets.only(top: 10, left: 4), + child: SizedBox( + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Color(0xFF114D8B), + foregroundColor: Colors.white, + disabledBackgroundColor: Color(0xFF114D8B), + disabledForegroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide(color: Color(0xFF114D8B), width: 2), + ), + padding: EdgeInsets.symmetric( + horizontal: 20, + vertical: 12, + ), ), - padding: EdgeInsets.symmetric( - horizontal: 20, - vertical: 12, - ), - ), - onPressed: () {handleSubmit();}, - child: Row( - mainAxisSize: - MainAxisSize.min, // Ensures content fits nicely - children: [ - Text( - "Search", - style: GoogleFonts.poppins( - fontSize: isDesktop ? 13 : 11, + onPressed: () { + handleSubmit(); + }, + child: Row( + mainAxisSize: + MainAxisSize.min, // Ensures content fits nicely + children: [ + Text( + "Search", + style: GoogleFonts.poppins( + fontSize: isDesktop ? 13 : 11, + ), ), - ), - SizedBox(width: 8), // spacing between icon and text - Icon( - Icons.search, - size: 15, - color: Colors.white, - ), - ], + SizedBox(width: 8), // spacing between icon and text + Icon(Icons.search, size: 15, color: Colors.white), + ], + ), ), ), ), @@ -570,10 +682,7 @@ class _AdvancePurchaseState extends State labelColor: Colors.black, unselectedLabelColor: Colors.grey, indicatorColor: Color(0xFF114D8B), - tabs: [ - Tab(text: "Domestic"), - Tab(text: "International"), - ], + tabs: [Tab(text: "Domestic"), Tab(text: "International")], ), SizedBox(height: 5), Container( @@ -587,441 +696,873 @@ class _AdvancePurchaseState extends State ? Center(child: CircularProgressIndicator()) : domesticData.isEmpty ? Center( - child: Padding( - padding: EdgeInsets.all(16), - child: Text( - "No data found", - style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w500), - ), - ), - ) - : Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - /// Title on the left - Expanded( - child: Text( - "Domestic Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", - style: GoogleFonts.poppins( - fontSize: 13, - fontWeight: FontWeight.w500, - color: Colors.grey[700], - ), - overflow: TextOverflow.ellipsis, // Ensures title doesn't overflow - ), + child: Padding( + padding: EdgeInsets.all(16), + child: Text( + "No data found", + style: GoogleFonts.poppins( + fontSize: 14, + fontWeight: FontWeight.w500, ), - SizedBox(width: 16), - /// Buttons on the right - Row( + ), + ), + ) + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, + vertical: 8, + ), + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, children: [ - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFF114D8B), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide(color: Color(0xFF114D8B), width: 2), + /// Title on the left + Expanded( + child: Text( + "Domestic Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", + style: GoogleFonts.poppins( + fontSize: 13, + fontWeight: FontWeight.w500, + color: Colors.grey[700], ), - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), - ), - onPressed: () { - // Excel export logic - }, - child: Row( - children: [ - Text( - "Excel", - style: GoogleFonts.poppins( - fontSize: isDesktop ? 13 : 11, - color: Colors.white, - ), - ), - SizedBox(width: 8), - Icon(Icons.file_present_outlined, size: 15, color: Colors.white), - ], - ), - ), - SizedBox(width: 10), - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFF114D8B), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide(color: Color(0xFF114D8B), width: 2), - ), - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), - ), - onPressed: () { - // PDF export logic - }, - child: Row( - children: [ - Text( - "PDF", - style: GoogleFonts.poppins( - fontSize: isDesktop ? 13 : 11, - color: Colors.white, - ), - ), - SizedBox(width: 8), - Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), - ], + overflow: + TextOverflow + .ellipsis, // Ensures title doesn't overflow ), ), + // SizedBox(width: 16), + // /// Buttons on the right + // Row( + // children: [ + // ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: Color(0xFF114D8B), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8), + // side: BorderSide(color: Color(0xFF114D8B), width: 2), + // ), + // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + // ), + // onPressed: handleDownload, + // child: Row( + // children: [ + // Text( + // "Excel", + // style: GoogleFonts.poppins( + // fontSize: isDesktop ? 13 : 11, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 8), + // Icon(Icons.file_present_outlined, size: 15, color: Colors.white), + // ], + // ), + // ), + // SizedBox(width: 10), + // ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: Color(0xFF114D8B), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8), + // side: BorderSide(color: Color(0xFF114D8B), width: 2), + // ), + // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + // ), + // onPressed: handleDownload, + // child: Row( + // children: [ + // Text( + // "PDF", + // style: GoogleFonts.poppins( + // fontSize: isDesktop ? 13 : 11, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 8), + // Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), + // ], + // ), + // ), + // ], + // ), ], ), - ], - ), - ), + ), - /* For pagination for list ... */ - // Expanded( - // child: SingleChildScrollView( - // scrollDirection: Axis.horizontal, - // child: SingleChildScrollView( - // scrollDirection: Axis.vertical, - // child: DataTable( - // dividerThickness: 0.5, - // columnSpacing: isDesktop ? 30.0 : 24.0, - // border: TableBorder( - // horizontalInside: BorderSide( - // width: 0.5, - // color: Colors.grey.shade200, - // ), - // ), - // columns: [ - // DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - // DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - // DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - // DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - // DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - // DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - // DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - // ], - // rows: domesticData.map((entry) { - // return DataRow(cells: [ - // DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), - // DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), - // DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), - // DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), - // DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - // DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - // DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), - // ]); - // }).toList(), - // ), - // ), - // ), - // ), - // -------- Table with Pagination -------- - Expanded( - child: LayoutBuilder( - builder: (context, constraints) { - final double minWidth = isDesktop ? constraints.maxWidth : 1300; + /* For pagination for list ... */ + // Expanded( + // child: SingleChildScrollView( + // scrollDirection: Axis.horizontal, + // child: SingleChildScrollView( + // scrollDirection: Axis.vertical, + // child: DataTable( + // dividerThickness: 0.5, + // columnSpacing: isDesktop ? 30.0 : 24.0, + // border: TableBorder( + // horizontalInside: BorderSide( + // width: 0.5, + // color: Colors.grey.shade200, + // ), + // ), + // columns: [ + // DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // ], + // rows: domesticData.map((entry) { + // return DataRow(cells: [ + // DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), + // ]); + // }).toList(), + // ), + // ), + // ), + // ), + // -------- Table with Pagination -------- + Expanded( + child: LayoutBuilder( + builder: (context, constraints) { + final double minWidth = + isDesktop ? constraints.maxWidth : 1300; - // Pagination logic - List> paginatedDomestic = domesticData - .skip(currentPage1 * itemsPerPage1) - .take(itemsPerPage1) - .toList(); + // Pagination logic + List> + paginatedDomestic = + domesticData + .skip(currentPage1 * itemsPerPage1) + .take(itemsPerPage1) + .toList(); - return Column( - children: [ - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: ConstrainedBox( - constraints: BoxConstraints(minWidth: minWidth), + return Column( + children: [ + Expanded( child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: DataTable( - dividerThickness: 0.5, - columnSpacing: isDesktop ? 30.0 : 24.0, - border: TableBorder( - horizontalInside: BorderSide( - width: 0.5, - color: Colors.grey.shade200, + scrollDirection: Axis.horizontal, + child: ConstrainedBox( + constraints: BoxConstraints( + minWidth: minWidth, + ), + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: DataTable( + dividerThickness: 0.5, + columnSpacing: + isDesktop ? 30.0 : 24.0, + border: TableBorder( + horizontalInside: + BorderSide( + width: 0.5, + color: + Colors + .grey + .shade200, + ), + ), + columns: [ + DataColumn( + label: Text( + 'Plan Id', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Employee Code', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'SO Number', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Department', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Flight Trip Type', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Plan Trip Type', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Sector', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Class', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Travel Date', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + ], + rows: + paginatedDomestic.map(( + entry, + ) { + final TravelDate = + DateFormat( + 'dd-MM-yyyy', + ).format( + DateTime.parse( + entry['flight_travel_date'], + ), + ); + return DataRow( + cells: [ + DataCell( + Text( + '${entry['plan_id']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['employee_code']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['so_number']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['functional_department']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['flight_trip_type']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['plan_trip_type']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['sector']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['flight_class']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + TravelDate, + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + ], + ); + }).toList(), ), ), - columns: [ - DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - ], - rows: paginatedDomestic.map((entry) { - return DataRow(cells: [ - DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), - ]); - }).toList(), ), ), ), - ), - ), - // Pagination controls - PaginationControls( - currentPage: currentPage1, - itemsPerPage: itemsPerPage1, - totalItems: domesticData.length, - activeColor: layoutColor, - onPageChanged: (page) { - setState(() { - currentPage1 = page; - }); - }, - onItemsPerPageChanged: (items) { - setState(() { - itemsPerPage1 = items; - currentPage1 = 0; - }); - }, - ), - ], - ); - }, - ), + // Pagination controls + PaginationControls( + currentPage: currentPage1, + itemsPerPage: itemsPerPage1, + totalItems: domesticData.length, + activeColor: layoutColor, + onPageChanged: (page) { + setState(() { + currentPage1 = page; + }); + }, + onItemsPerPageChanged: (items) { + setState(() { + itemsPerPage1 = items; + currentPage1 = 0; + }); + }, + ), + ], + ); + }, + ), + ), + ], ), - ], - ), - // International Tab internationalData.isEmpty ? Center( - child: Padding( - padding: EdgeInsets.all(16), - child: Text( - "No data found", - style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w500), - ), - ), - ) - : Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Padding( - // padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), - // child: Row( - // mainAxisAlignment: MainAxisAlignment.spaceBetween, - // crossAxisAlignment: CrossAxisAlignment.center, - // children: [ - // /// Title on the left - // Expanded( - // child: Text( - // "International Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", - // style: GoogleFonts.poppins( - // fontSize: 13, - // fontWeight: FontWeight.w500, - // color: Colors.grey[700], - // ), - // overflow: TextOverflow.ellipsis, // Ensures title doesn't overflow - // ), - // ), - // SizedBox(width: 16), - // /// Buttons on the right - // Row( - // children: [ - // ElevatedButton( - // style: ElevatedButton.styleFrom( - // backgroundColor: Color(0xFF114D8B), - // shape: RoundedRectangleBorder( - // borderRadius: BorderRadius.circular(8), - // side: BorderSide(color: Color(0xFF114D8B), width: 2), - // ), - // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), - // ), - // onPressed: () { - // // Excel export logic - // }, - // child: Row( - // children: [ - // Text( - // "Excel", - // style: GoogleFonts.poppins( - // fontSize: isDesktop ? 13 : 11, - // color: Colors.white, - // ), - // ), - // SizedBox(width: 8), - // Icon(Icons.file_present_outlined, size: 15, color: Colors.white), - // ], - // ), - // ), - // SizedBox(width: 10), - // ElevatedButton( - // style: ElevatedButton.styleFrom( - // backgroundColor: Color(0xFF114D8B), - // shape: RoundedRectangleBorder( - // borderRadius: BorderRadius.circular(8), - // side: BorderSide(color: Color(0xFF114D8B), width: 2), - // ), - // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), - // ), - // onPressed: () { - // // PDF export logic - // }, - // child: Row( - // children: [ - // Text( - // "PDF", - // style: GoogleFonts.poppins( - // fontSize: isDesktop ? 13 : 11, - // color: Colors.white, - // ), - // ), - // SizedBox(width: 8), - // Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), - // ], - // ), - // ), - // ], - // ), - // ], - // ), - // ), - // Expanded( - // child: SingleChildScrollView( - // scrollDirection: Axis.horizontal, - // child: SingleChildScrollView( - // scrollDirection: Axis.vertical, - // child: DataTable( - // dividerThickness: 0.5, - // columnSpacing: isDesktop ? 24.0 : 16.0, - // border: TableBorder( - // horizontalInside: BorderSide( - // width: 0.5, - // color: Colors.grey.shade200, - // ), - // ), - // columns: [ - // DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - // DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - // DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - // DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - // DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - // DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - // DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - // ], - // rows: internationalData.map((entry) { - // return DataRow(cells: [ - // DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), - // DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), - // DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), - // DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), - // DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - // DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - // DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), - // ]); - // }).toList(), - // ), - // ), - // ), - // ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), - child: Text( - "International Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", - style: GoogleFonts.poppins(fontSize: 13, fontWeight: FontWeight.w500, color: Colors.grey[700]), + child: Padding( + padding: EdgeInsets.all(16), + child: Text( + "No data found", + style: GoogleFonts.poppins( + fontSize: 14, + fontWeight: FontWeight.w500, + ), + ), ), - ), - Container( - height : isDesktop ? MediaQuery.of(context).size.height * 0.51 : 200, - // color:Colors.amberAccent, - child: LayoutBuilder( - builder: (context, constraints) { - final double minWidth = isDesktop ? constraints.maxWidth : 1300; + ) + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Padding( + // padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), + // child: Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // crossAxisAlignment: CrossAxisAlignment.center, + // children: [ + // /// Title on the left + // Expanded( + // child: Text( + // "International Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", + // style: GoogleFonts.poppins( + // fontSize: 13, + // fontWeight: FontWeight.w500, + // color: Colors.grey[700], + // ), + // overflow: TextOverflow.ellipsis, // Ensures title doesn't overflow + // ), + // ), + // SizedBox(width: 16), + // /// Buttons on the right + // Row( + // children: [ + // ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: Color(0xFF114D8B), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8), + // side: BorderSide(color: Color(0xFF114D8B), width: 2), + // ), + // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + // ), + // onPressed: () { + // // Excel export logic + // }, + // child: Row( + // children: [ + // Text( + // "Excel", + // style: GoogleFonts.poppins( + // fontSize: isDesktop ? 13 : 11, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 8), + // Icon(Icons.file_present_outlined, size: 15, color: Colors.white), + // ], + // ), + // ), + // SizedBox(width: 10), + // ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: Color(0xFF114D8B), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8), + // side: BorderSide(color: Color(0xFF114D8B), width: 2), + // ), + // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + // ), + // onPressed: () { + // // PDF export logic + // }, + // child: Row( + // children: [ + // Text( + // "PDF", + // style: GoogleFonts.poppins( + // fontSize: isDesktop ? 13 : 11, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 8), + // Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), + // ], + // ), + // ), + // ], + // ), + // ], + // ), + // ), + // Expanded( + // child: SingleChildScrollView( + // scrollDirection: Axis.horizontal, + // child: SingleChildScrollView( + // scrollDirection: Axis.vertical, + // child: DataTable( + // dividerThickness: 0.5, + // columnSpacing: isDesktop ? 24.0 : 16.0, + // border: TableBorder( + // horizontalInside: BorderSide( + // width: 0.5, + // color: Colors.grey.shade200, + // ), + // ), + // columns: [ + // DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // ], + // rows: internationalData.map((entry) { + // return DataRow(cells: [ + // DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), + // ]); + // }).toList(), + // ), + // ), + // ), + // ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, + vertical: 8, + ), + child: Text( + "International Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", + style: GoogleFonts.poppins( + fontSize: 13, + fontWeight: FontWeight.w500, + color: Colors.grey[700], + ), + ), + ), + Container( + height: + isDesktop + ? MediaQuery.of(context).size.height * + 0.51 + : 200, + // color:Colors.amberAccent, + child: LayoutBuilder( + builder: (context, constraints) { + final double minWidth = + isDesktop ? constraints.maxWidth : 1300; - // Pagination logic - List> paginatedInternational = internationalData - .skip(currentPage2 * itemsPerPage2) - .take(itemsPerPage2) - .toList(); + // Pagination logic + List> + paginatedInternational = + internationalData + .skip(currentPage2 * itemsPerPage2) + .take(itemsPerPage2) + .toList(); - return Column( - children: [ - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: ConstrainedBox( - constraints: BoxConstraints(minWidth: minWidth), + return Column( + children: [ + Expanded( child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: DataTable( - dividerThickness: 0.5, - columnSpacing: isDesktop ? 30.0 : 24.0, - border: TableBorder( - horizontalInside: BorderSide( - width: 0.5, - color: Colors.grey.shade200, + scrollDirection: Axis.horizontal, + child: ConstrainedBox( + constraints: BoxConstraints( + minWidth: minWidth, + ), + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: DataTable( + dividerThickness: 0.5, + columnSpacing: + isDesktop ? 30.0 : 24.0, + border: TableBorder( + horizontalInside: + BorderSide( + width: 0.5, + color: + Colors + .grey + .shade200, + ), + ), + columns: [ + DataColumn( + label: Text( + 'Plan Id', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Employee Code', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'SO Number', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Department', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Flight Trip Type', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Plan Trip Type', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Sector', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Class', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Travel Date', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + ], + rows: + paginatedInternational.map(( + entry, + ) { + final TravelDate = + DateFormat( + 'dd-MM-yyyy', + ).format( + DateTime.parse( + entry['flight_travel_date'], + ), + ); + return DataRow( + cells: [ + DataCell( + Text( + '${entry['plan_id']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['employee_code']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['so_number']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['functional_department']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['flight_trip_type']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['plan_trip_type']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['sector']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['flight_class']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + TravelDate, + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + ], + ); + }).toList(), ), ), - columns: [ - DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - ], - rows: paginatedInternational.map((entry) { - return DataRow(cells: [ - DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), - ]); - }).toList(), ), ), ), - ), - ), - // Pagination controls - PaginationControls( - currentPage: currentPage2, - itemsPerPage: itemsPerPage2, - totalItems: internationalData.length, - activeColor: layoutColor, - onPageChanged: (page) { - setState(() { - currentPage2 = page; - }); - }, - onItemsPerPageChanged: (items) { - setState(() { - itemsPerPage2 = items; - currentPage2 = 0; - }); - }, - ), - ], - ); - }, - ), + // Pagination controls + PaginationControls( + currentPage: currentPage2, + itemsPerPage: itemsPerPage2, + totalItems: internationalData.length, + activeColor: layoutColor, + onPageChanged: (page) { + setState(() { + currentPage2 = page; + }); + }, + onItemsPerPageChanged: (items) { + setState(() { + itemsPerPage2 = items; + currentPage2 = 0; + }); + }, + ), + ], + ); + }, + ), + ), + ], ), - ], - ), ], ), ), @@ -1033,4 +1574,4 @@ class _AdvancePurchaseState extends State ), ); } -} \ No newline at end of file +} diff --git a/lib/Screens/reports/misForex.dart b/lib/Screens/reports/misForex.dart index 516918a..6a18e94 100644 --- a/lib/Screens/reports/misForex.dart +++ b/lib/Screens/reports/misForex.dart @@ -1,5 +1,7 @@ import 'dart:convert'; import 'dart:core'; +import 'dart:typed_data'; + import 'package:go_router/go_router.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; @@ -8,23 +10,23 @@ import 'package:frontend/config/apiUrl.dart'; import 'package:intl/intl.dart'; import 'package:responsive_builder/responsive_builder.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:universal_html/html.dart' as html; import '../../routes/custom_appBar.dart'; import '../../routes/custom_drawer.dart'; -import '../../routes/mainLayout.dart'; import '../../services/apiService.dart'; import '../../utils/auth_utils.dart'; import '../../utils/pagination.dart'; import '../../widgets/custom_text_field.dart'; -class AdvancePurchase extends StatefulWidget { - const AdvancePurchase({super.key}); +class MISforex extends StatefulWidget { + const MISforex({super.key}); @override - _AdvancePurchaseState createState() => _AdvancePurchaseState(); + _MISforexState createState() => _MISforexState(); } -class _AdvancePurchaseState extends State +class _MISforexState extends State with SingleTickerProviderStateMixin { final ApiService apiService = ApiService(); @@ -33,7 +35,6 @@ class _AdvancePurchaseState extends State String? roleUser; String? token; - Color? layoutColor; Color? bodyColor; @@ -42,12 +43,12 @@ class _AdvancePurchaseState extends State int currentPage2 = 0; int itemsPerPage2 = 10; late TabController _tabController; - final List tabNames = ['Domestic', 'International']; + String selectedTabName = 'domestic'; Map focusNodes = {}; Map focusStates = {}; Map textControllers = {}; Map errorMessages = {}; - // Map advancePurchaseReport = {}; + // Map MISforexReport = {}; List> domesticData = []; List> internationalData = []; // Map domesticData = {}; @@ -59,6 +60,7 @@ class _AdvancePurchaseState extends State void initState() { super.initState(); loadInitialData(); + _checkAuthAndLoadData(); if (!textControllers.containsKey("from_date")) { textControllers["from_date"] = TextEditingController(); } @@ -83,6 +85,9 @@ class _AdvancePurchaseState extends State _tabController.addListener(() { if (_tabController.indexIsChanging == false) { // Only fire when tab change is complete + setState(() { + selectedTabName = getTabName(_tabController.index); + }); print(" :) :X Selected Tab: ${getTabName(_tabController.index)}"); } }); @@ -97,17 +102,18 @@ class _AdvancePurchaseState extends State }); getToken(); - // fetchAdvancePurchaseReport(); + // fetchMISforexReport(); } String getTabName(int index) { switch (index) { case 0: - return "Domestic"; + return "domestic"; case 1: - return "International"; + return "international"; default: - return "Unknown"; + // return "Unknown"; + return "domestic"; } } @@ -123,15 +129,37 @@ class _AdvancePurchaseState extends State String? layoutString = await getLayoutColor(); String? bodyStringColor = await getBodyColor(); - setState(() { - layoutColor = layoutString != null ? Color(int.parse(layoutString)) - : Colors.redAccent; + layoutColor = + layoutString != null + ? Color(int.parse(layoutString)) + : Colors.redAccent; - bodyColor = bodyStringColor != null ? Color(int.parse(bodyStringColor)) - : Colors.white; + bodyColor = + bodyStringColor != null + ? Color(int.parse(bodyStringColor)) + : Colors.white; }); + } + void _checkAuthAndLoadData() async { + final String? token = await getToken(); // Your async function to get token + + if (token == null || token.isEmpty) { + // Token doesn't exist → redirect to login + context.go( + "/", + ); // or use: router.go("/") if you're using `GoRouter` directly + return; + } + if (!mounted) return; + try { + WidgetsBinding.instance.addPostFrameCallback((_) { + loadInitialData(); + }); + } catch (e) { + print("service report : $e"); + } } Future initializeData() async { @@ -140,14 +168,12 @@ class _AdvancePurchaseState extends State orgId = await getOrgId(); roleUser = await getRoleUser(); - if (token == null || userId == null) { print("Token or USerId missing"); return; } } - Future getUserId() async { final prefs = await SharedPreferences.getInstance(); final String? userDataString = prefs.getString('user_data'); @@ -183,21 +209,30 @@ class _AdvancePurchaseState extends State return prefs.getString('auth_token'); } - Future handleSubmit() async { errorMessages.remove("from_date"); errorMessages.remove("to_date"); setState(() { domesticData = []; internationalData = []; + currentPage1 = 0; + itemsPerPage1 = 10; + currentPage2 = 0; + itemsPerPage2 = 10; }); final fromDateText = textControllers["from_date"]?.text; final toDateText = textControllers["to_date"]?.text; - if (fromDateText == null || fromDateText.isEmpty || - toDateText == null || toDateText.isEmpty) { - errorMessages["from_date"] = "Required"; - errorMessages["to_date"] = "Required"; + if (fromDateText == null || + fromDateText.isEmpty || + toDateText == null || + toDateText.isEmpty) { + fromDateText == null || fromDateText.isEmpty + ? errorMessages["from_date"] = "Required" + : errorMessages.remove("from_date"); + toDateText == null || toDateText.isEmpty + ? errorMessages["to_date"] = "Required" + : errorMessages.remove("to_date"); setState(() {}); return; } @@ -213,7 +248,9 @@ class _AdvancePurchaseState extends State setState(() {}); return; } - setState(() { loaderFlag = true; }); + setState(() { + loaderFlag = true; + }); // Format for API request final formattedfromDate = DateFormat('yyyy-MM-dd').format(fromDate); @@ -224,35 +261,88 @@ class _AdvancePurchaseState extends State loaderFlag = true; try { final result = await apiService.CallReports( - 'advancePurchaseReport', - formattedfromDate, - formattedtoDate, + 'misForexReport', + jsonEncode({ + "fromDate": '$formattedfromDate', + "toDate": '$formattedtoDate', + }), ); setState(() { - domesticData = List>.from(result['data']['domestic'] ?? []); - internationalData = List>.from(result['data']['international'] ?? []); + // domesticData = List>.from(result['data']['domestic'] ?? []); + internationalData = List>.from( + result['status'] == 'success' + ? result['data']['international'] ?? [] + : [], + ); loaderFlag = false; }); } catch (e) { // handle error setState(() { loaderFlag = false; - domesticData = []; + // domesticData = []; internationalData = []; }); } } + Future handleDownload() async { + final dateFormat = DateFormat('dd-MM-yyyy'); + + if (textControllers["from_date"]!.text.isEmpty || + textControllers["to_date"]!.text.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: Colors.redAccent, + content: Text("Please choose a valid date range."), + behavior: SnackBarBehavior.floating, + ), + ); + return; + } + + final DateTime fromDate = dateFormat.parse( + textControllers["from_date"]!.text, + ); + final DateTime toDate = dateFormat.parse(textControllers["to_date"]!.text); + + final formattedFromDate = DateFormat('yyyy-MM-dd').format(fromDate); + final formattedToDate = DateFormat('yyyy-MM-dd').format(toDate); + + final name = + 'MIS Forex - $selectedTabName Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})'; + final safeName = name.replaceAll(RegExp(r'[^\w\s-]'), ''); + final excelName = '$safeName'; + + final result = await apiService.reportExcelDownload( + 'misForexReport', + jsonEncode({ + "fromDate": formattedFromDate, + "toDate": formattedToDate, + "export": selectedTabName, + }), + excelName, + ); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: Colors.green, + content: Text(result as String), + behavior: SnackBarBehavior.floating, + ), + ); + } + @override // Widget build(BuildContext context) { // // TODO: implement build // throw UnimplementedError(); // } - Widget build(BuildContext context) { return ResponsiveBuilder( builder: (context, sizingInfo) { - bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop; + bool isDesktop = + sizingInfo.deviceScreenType == DeviceScreenType.desktop; return Scaffold( backgroundColor: Color(0xFFf5f5f5), @@ -260,21 +350,21 @@ class _AdvancePurchaseState extends State 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), + 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), // const Expanded(child: Center(child: Text("User Page Content"))), - Expanded(child: buildAdvancePurchaseLayout(isDesktop)) + Expanded(child: buildMISforexLayout(isDesktop)), ], ), ), @@ -283,22 +373,21 @@ class _AdvancePurchaseState extends State ); } - Widget buildAdvancePurchaseLayout(bool isDesktop) { - return Container( child: buildAdvancePurchaseFormLayout(isDesktop) ); + Widget buildMISforexLayout(bool isDesktop) { + return Container(child: buildMISforexFormLayout(isDesktop)); } - Widget buildAdvancePurchaseFormLayout(bool isDesktop) { + Widget buildMISforexFormLayout(bool isDesktop) { return Container( margin: isDesktop ? EdgeInsets.all(10.0) : null, padding: const EdgeInsets.only(top: 5, bottom: 5, left: 20, right: 20), // color: Colors.brown, - height: isDesktop - ? MediaQuery.of(context).size.height * 1 - : MediaQuery.of(context).size.height, + height: + isDesktop + ? MediaQuery.of(context).size.height * 1 + : MediaQuery.of(context).size.height, decoration: BoxDecoration( - border: isDesktop - ? Border.all(width: 2, color: Colors.white) - : null, + border: isDesktop ? Border.all(width: 2, color: Colors.white) : null, color: isDesktop ? Colors.white : Color(0xFFFCFCFC), ), child: Column( @@ -309,7 +398,7 @@ class _AdvancePurchaseState extends State mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - 'Advance Purchase', + 'MIS Forex Report', style: GoogleFonts.poppins( fontSize: isDesktop ? 16 : 14, fontWeight: FontWeight.w600, @@ -325,11 +414,12 @@ class _AdvancePurchaseState extends State borderRadius: BorderRadius.circular(8), side: BorderSide(color: Color(0xFF114D8B), width: 2), ), - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + padding: EdgeInsets.symmetric( + horizontal: 20, + vertical: 12, + ), ), - onPressed: () { - // Your Excel export logic here - }, + onPressed: handleDownload, child: Row( children: [ Text( @@ -340,37 +430,41 @@ class _AdvancePurchaseState extends State ), ), SizedBox(width: 8), - Icon(Icons.file_present_outlined, size: 15, color: Colors.white), - ], - ), - ), - SizedBox(width: 10), - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFF114D8B), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide(color: Color(0xFF114D8B), width: 2), - ), - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), - ), - onPressed: () { - // Your PDF export logic here - }, - child: Row( - children: [ - Text( - "PDF", - style: GoogleFonts.poppins( - fontSize: isDesktop ? 13 : 11, - color: Colors.white, - ), + Icon( + Icons.file_present_outlined, + size: 15, + color: Colors.white, ), - SizedBox(width: 8), - Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), ], ), ), + // SizedBox(width: 10), + // ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: Color(0xFF114D8B), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8), + // side: BorderSide(color: Color(0xFF114D8B), width: 2), + // ), + // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + // ), + // onPressed: () { + // // Your PDF export logic here + // }, + // child: Row( + // children: [ + // Text( + // "PDF", + // style: GoogleFonts.poppins( + // fontSize: isDesktop ? 13 : 11, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 8), + // Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), + // ], + // ), + // ), ], ), ], @@ -406,8 +500,9 @@ class _AdvancePurchaseState extends State lastDate: DateTime(2100), ); if (pickedDate != null) { - textControllers["from_date"]?.text = - DateFormat('dd-MM-yyyy').format(pickedDate); + textControllers["from_date"]?.text = DateFormat( + 'dd-MM-yyyy', + ).format(pickedDate); } }, child: AbsorbPointer( @@ -422,9 +517,12 @@ class _AdvancePurchaseState extends State fontSize: 12, color: Colors.grey, ), - floatingLabelBehavior: FloatingLabelBehavior.never, + floatingLabelBehavior: + FloatingLabelBehavior.never, border: InputBorder.none, - contentPadding: const EdgeInsets.symmetric(vertical: 16), + contentPadding: const EdgeInsets.symmetric( + vertical: 16, + ), suffixIcon: const Icon( Icons.calendar_today, size: 16, @@ -465,10 +563,13 @@ class _AdvancePurchaseState extends State height: 40, child: GestureDetector( onTap: () async { - final fromDateText = textControllers["from_date"]?.text; + final fromDateText = + textControllers["from_date"]?.text; DateTime? mintoDate; if (fromDateText != null && fromDateText.isNotEmpty) { - mintoDate = DateFormat('dd-MM-yyyy').parse(fromDateText); + mintoDate = DateFormat( + 'dd-MM-yyyy', + ).parse(fromDateText); } final pickedDate = await showDatePicker( @@ -479,8 +580,9 @@ class _AdvancePurchaseState extends State ); if (pickedDate != null) { - textControllers["to_date"]?.text = - DateFormat('dd-MM-yyyy').format(pickedDate); + textControllers["to_date"]?.text = DateFormat( + 'dd-MM-yyyy', + ).format(pickedDate); } }, child: AbsorbPointer( @@ -491,10 +593,16 @@ class _AdvancePurchaseState extends State style: const TextStyle(fontSize: 12), decoration: const InputDecoration( labelText: "Select Date", - labelStyle: TextStyle(fontSize: 12, color: Colors.grey), - floatingLabelBehavior: FloatingLabelBehavior.never, + labelStyle: TextStyle( + fontSize: 12, + color: Colors.grey, + ), + floatingLabelBehavior: + FloatingLabelBehavior.never, border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(vertical: 16), + contentPadding: EdgeInsets.symmetric( + vertical: 16, + ), suffixIcon: Icon( Icons.calendar_today, size: 16, @@ -513,46 +621,48 @@ class _AdvancePurchaseState extends State style: const TextStyle(color: Colors.red, fontSize: 12), maxLines: 2, // Allow it to wrap onto two lines overflow: - TextOverflow.ellipsis, // Add ellipsis if it still overflows + TextOverflow + .ellipsis, // Add ellipsis if it still overflows ), ], ], ), if (isDesktop) Spacer() else SizedBox(height: 8), - SizedBox( - child: ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFF114D8B), - foregroundColor: Colors.white, - disabledBackgroundColor: Color(0xFF114D8B), - disabledForegroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide(color: Color(0xFF114D8B), width: 2), + Padding( + padding: EdgeInsets.only(top: 10, left: 4), + child: SizedBox( + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Color(0xFF114D8B), + foregroundColor: Colors.white, + disabledBackgroundColor: Color(0xFF114D8B), + disabledForegroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide(color: Color(0xFF114D8B), width: 2), + ), + padding: EdgeInsets.symmetric( + horizontal: 20, + vertical: 12, + ), ), - padding: EdgeInsets.symmetric( - horizontal: 20, - vertical: 12, - ), - ), - onPressed: () {handleSubmit();}, - child: Row( - mainAxisSize: - MainAxisSize.min, // Ensures content fits nicely - children: [ - Text( - "Search", - style: GoogleFonts.poppins( - fontSize: isDesktop ? 13 : 11, + onPressed: () { + handleSubmit(); + }, + child: Row( + mainAxisSize: + MainAxisSize.min, // Ensures content fits nicely + children: [ + Text( + "Search", + style: GoogleFonts.poppins( + fontSize: isDesktop ? 13 : 11, + ), ), - ), - SizedBox(width: 8), // spacing between icon and text - Icon( - Icons.search, - size: 15, - color: Colors.white, - ), - ], + SizedBox(width: 8), // spacing between icon and text + Icon(Icons.search, size: 15, color: Colors.white), + ], + ), ), ), ), @@ -561,476 +671,334 @@ class _AdvancePurchaseState extends State SizedBox(height: 5), // ------------------- Third Row ------------------- - DefaultTabController( - length: 2, - child: Column( - children: [ - TabBar( - controller: _tabController, - labelColor: Colors.black, - unselectedLabelColor: Colors.grey, - indicatorColor: Color(0xFF114D8B), - tabs: [ - Tab(text: "Domestic"), - Tab(text: "International"), - ], - ), - SizedBox(height: 5), - Container( - // color:Colors.grey, - height: MediaQuery.of(context).size.height * 0.6, - // height: 200, // Or use Expanded for flexible height - child: TabBarView( - controller: _tabController, - children: [ - loaderFlag - ? Center(child: CircularProgressIndicator()) - : domesticData.isEmpty - ? Center( - child: Padding( - padding: EdgeInsets.all(16), - child: Text( - "No data found", - style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w500), - ), - ), - ) - : Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - /// Title on the left - Expanded( - child: Text( - "Domestic Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", - style: GoogleFonts.poppins( - fontSize: 13, - fontWeight: FontWeight.w500, - color: Colors.grey[700], - ), - overflow: TextOverflow.ellipsis, // Ensures title doesn't overflow - ), - ), - SizedBox(width: 16), - /// Buttons on the right - Row( - children: [ - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFF114D8B), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide(color: Color(0xFF114D8B), width: 2), - ), - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), - ), - onPressed: () { - // Excel export logic - }, - child: Row( - children: [ - Text( - "Excel", - style: GoogleFonts.poppins( - fontSize: isDesktop ? 13 : 11, - color: Colors.white, - ), - ), - SizedBox(width: 8), - Icon(Icons.file_present_outlined, size: 15, color: Colors.white), - ], - ), - ), - SizedBox(width: 10), - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFF114D8B), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide(color: Color(0xFF114D8B), width: 2), - ), - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), - ), - onPressed: () { - // PDF export logic - }, - child: Row( - children: [ - Text( - "PDF", - style: GoogleFonts.poppins( - fontSize: isDesktop ? 13 : 11, - color: Colors.white, - ), - ), - SizedBox(width: 8), - Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), - ], - ), - ), - ], - ), - ], - ), - ), - - /* For pagination for list ... */ - // Expanded( - // child: SingleChildScrollView( - // scrollDirection: Axis.horizontal, - // child: SingleChildScrollView( - // scrollDirection: Axis.vertical, - // child: DataTable( - // dividerThickness: 0.5, - // columnSpacing: isDesktop ? 30.0 : 24.0, - // border: TableBorder( - // horizontalInside: BorderSide( - // width: 0.5, - // color: Colors.grey.shade200, - // ), - // ), - // columns: [ - // DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - // DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - // DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - // DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - // DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - // DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - // DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - // ], - // rows: domesticData.map((entry) { - // return DataRow(cells: [ - // DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), - // DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), - // DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), - // DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), - // DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - // DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - // DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), - // ]); - // }).toList(), - // ), - // ), - // ), - // ), - // -------- Table with Pagination -------- - Expanded( - child: LayoutBuilder( - builder: (context, constraints) { - final double minWidth = isDesktop ? constraints.maxWidth : 1300; - - // Pagination logic - List> paginatedDomestic = domesticData - .skip(currentPage1 * itemsPerPage1) - .take(itemsPerPage1) - .toList(); - - return Column( - children: [ - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: ConstrainedBox( - constraints: BoxConstraints(minWidth: minWidth), - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: DataTable( - dividerThickness: 0.5, - columnSpacing: isDesktop ? 30.0 : 24.0, - border: TableBorder( - horizontalInside: BorderSide( - width: 0.5, - color: Colors.grey.shade200, - ), - ), - columns: [ - DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - ], - rows: paginatedDomestic.map((entry) { - return DataRow(cells: [ - DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), - ]); - }).toList(), - ), - ), - ), - ), - ), - - // Pagination controls - PaginationControls( - currentPage: currentPage1, - itemsPerPage: itemsPerPage1, - totalItems: domesticData.length, - activeColor: layoutColor, - onPageChanged: (page) { - setState(() { - currentPage1 = page; - }); - }, - onItemsPerPageChanged: (items) { - setState(() { - itemsPerPage1 = items; - currentPage1 = 0; - }); - }, - ), - ], - ); - }, - ), - ), - ], - ), - - - // International Tab - internationalData.isEmpty - ? Center( - child: Padding( - padding: EdgeInsets.all(16), - child: Text( - "No data found", - style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w500), - ), - ), - ) - : Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Padding( - // padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), - // child: Row( - // mainAxisAlignment: MainAxisAlignment.spaceBetween, - // crossAxisAlignment: CrossAxisAlignment.center, - // children: [ - // /// Title on the left - // Expanded( - // child: Text( - // "International Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", - // style: GoogleFonts.poppins( - // fontSize: 13, - // fontWeight: FontWeight.w500, - // color: Colors.grey[700], - // ), - // overflow: TextOverflow.ellipsis, // Ensures title doesn't overflow - // ), - // ), - // SizedBox(width: 16), - // /// Buttons on the right - // Row( - // children: [ - // ElevatedButton( - // style: ElevatedButton.styleFrom( - // backgroundColor: Color(0xFF114D8B), - // shape: RoundedRectangleBorder( - // borderRadius: BorderRadius.circular(8), - // side: BorderSide(color: Color(0xFF114D8B), width: 2), - // ), - // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), - // ), - // onPressed: () { - // // Excel export logic - // }, - // child: Row( - // children: [ - // Text( - // "Excel", - // style: GoogleFonts.poppins( - // fontSize: isDesktop ? 13 : 11, - // color: Colors.white, - // ), - // ), - // SizedBox(width: 8), - // Icon(Icons.file_present_outlined, size: 15, color: Colors.white), - // ], - // ), - // ), - // SizedBox(width: 10), - // ElevatedButton( - // style: ElevatedButton.styleFrom( - // backgroundColor: Color(0xFF114D8B), - // shape: RoundedRectangleBorder( - // borderRadius: BorderRadius.circular(8), - // side: BorderSide(color: Color(0xFF114D8B), width: 2), - // ), - // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), - // ), - // onPressed: () { - // // PDF export logic - // }, - // child: Row( - // children: [ - // Text( - // "PDF", - // style: GoogleFonts.poppins( - // fontSize: isDesktop ? 13 : 11, - // color: Colors.white, - // ), - // ), - // SizedBox(width: 8), - // Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), - // ], - // ), - // ), - // ], - // ), - // ], - // ), - // ), - // Expanded( - // child: SingleChildScrollView( - // scrollDirection: Axis.horizontal, - // child: SingleChildScrollView( - // scrollDirection: Axis.vertical, - // child: DataTable( - // dividerThickness: 0.5, - // columnSpacing: isDesktop ? 24.0 : 16.0, - // border: TableBorder( - // horizontalInside: BorderSide( - // width: 0.5, - // color: Colors.grey.shade200, - // ), - // ), - // columns: [ - // DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - // DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - // DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - // DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - // DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - // DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - // DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - // ], - // rows: internationalData.map((entry) { - // return DataRow(cells: [ - // DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), - // DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), - // DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), - // DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), - // DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - // DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - // DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), - // ]); - // }).toList(), - // ), - // ), - // ), - // ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), + Column( + children: [ + Container( + height: MediaQuery.of(context).size.height * 0.6, + child: + internationalData.isEmpty + ? Center( + child: Padding( + padding: EdgeInsets.all(16), child: Text( - "International Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", - style: GoogleFonts.poppins(fontSize: 13, fontWeight: FontWeight.w500, color: Colors.grey[700]), + "No data found", + style: GoogleFonts.poppins( + fontSize: 14, + fontWeight: FontWeight.w500, + ), ), ), - Container( - height : isDesktop ? MediaQuery.of(context).size.height * 0.51 : 200, - // color:Colors.amberAccent, - child: LayoutBuilder( - builder: (context, constraints) { - final double minWidth = isDesktop ? constraints.maxWidth : 1300; + ) + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Header + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, + vertical: 8, + ), + child: Text( + "International Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", + style: GoogleFonts.poppins( + fontSize: 13, + fontWeight: FontWeight.w500, + color: Colors.grey[700], + ), + ), + ), + // Table container + Container( + height: + isDesktop + ? MediaQuery.of(context).size.height * + 0.51 + : 200, + child: LayoutBuilder( + builder: (context, constraints) { + final double minWidth = + isDesktop ? constraints.maxWidth : 1300; - // Pagination logic - List> paginatedInternational = internationalData - .skip(currentPage2 * itemsPerPage2) - .take(itemsPerPage2) - .toList(); + // Pagination logic + List> + paginatedInternational = + internationalData + .skip(currentPage2 * itemsPerPage2) + .take(itemsPerPage2) + .toList(); - return Column( - children: [ - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: ConstrainedBox( - constraints: BoxConstraints(minWidth: minWidth), - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: DataTable( - dividerThickness: 0.5, - columnSpacing: isDesktop ? 30.0 : 24.0, - border: TableBorder( - horizontalInside: BorderSide( - width: 0.5, - color: Colors.grey.shade200, + return Column( + children: [ + Expanded( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: ConstrainedBox( + constraints: BoxConstraints( + minWidth: minWidth, + ), + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: DataTable( + dividerThickness: 0.5, + columnSpacing: + isDesktop ? 30.0 : 24.0, + border: TableBorder( + horizontalInside: BorderSide( + width: 0.5, + color: Colors.grey.shade200, + ), ), + columns: [ + DataColumn( + label: Text( + 'Plan Id', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight.w600, + ), + ), + ), + DataColumn( + label: Text( + 'Employee Code', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight.w600, + ), + ), + ), + DataColumn( + label: Text( + 'Passenger Name', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight.w600, + ), + ), + ), + DataColumn( + label: Text( + 'SO Number', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight.w600, + ), + ), + ), + DataColumn( + label: Text( + 'Department', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight.w600, + ), + ), + ), + DataColumn( + label: Text( + 'Country', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight.w600, + ), + ), + ), + DataColumn( + label: Text( + 'From Date', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight.w600, + ), + ), + ), + DataColumn( + label: Text( + 'To Date', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight.w600, + ), + ), + ), + DataColumn( + label: Text( + 'Amount', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight.w600, + ), + ), + ), + ], + rows: + paginatedInternational.map(( + entry, + ) { + final forexFromDate = + DateFormat( + 'dd-MM-yyyy', + ).format( + DateTime.parse( + entry['forex_from_date'], + ), + ); + final forexToDate = + DateFormat( + 'dd-MM-yyyy', + ).format( + DateTime.parse( + entry['forex_to_date'], + ), + ); + return DataRow( + cells: [ + DataCell( + Text( + '${entry['plan_id']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['employee_code']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['passenger_name']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['so_number']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['functional_department']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['visiting_country']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + forexFromDate, + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + forexToDate, + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['amount']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + ], + ); + }).toList(), ), - columns: [ - DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - ], - rows: paginatedInternational.map((entry) { - return DataRow(cells: [ - DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), - ]); - }).toList(), ), ), ), ), - ), - - // Pagination controls - PaginationControls( - currentPage: currentPage2, - itemsPerPage: itemsPerPage2, - totalItems: internationalData.length, - activeColor: layoutColor, - onPageChanged: (page) { - setState(() { - currentPage2 = page; - }); - }, - onItemsPerPageChanged: (items) { - setState(() { - itemsPerPage2 = items; - currentPage2 = 0; - }); - }, - ), - ], - ); - }, + PaginationControls( + currentPage: currentPage2, + itemsPerPage: itemsPerPage2, + totalItems: internationalData.length, + activeColor: layoutColor, + onPageChanged: (page) { + setState(() { + currentPage2 = page; + }); + }, + onItemsPerPageChanged: (items) { + setState(() { + itemsPerPage2 = items; + currentPage2 = 0; + }); + }, + ), + ], + ); + }, + ), ), - ), - ], - ), - ], - ), - ), - ], - ), + ], + ), + ), + ], ), // SizedBox(height: 15), ], ), ); } -} \ No newline at end of file +} diff --git a/lib/Screens/reports/misHotel.dart b/lib/Screens/reports/misHotel.dart index 516918a..06626f0 100644 --- a/lib/Screens/reports/misHotel.dart +++ b/lib/Screens/reports/misHotel.dart @@ -1,5 +1,7 @@ import 'dart:convert'; import 'dart:core'; +import 'dart:typed_data'; + import 'package:go_router/go_router.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; @@ -8,23 +10,23 @@ import 'package:frontend/config/apiUrl.dart'; import 'package:intl/intl.dart'; import 'package:responsive_builder/responsive_builder.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:universal_html/html.dart' as html; import '../../routes/custom_appBar.dart'; import '../../routes/custom_drawer.dart'; -import '../../routes/mainLayout.dart'; import '../../services/apiService.dart'; import '../../utils/auth_utils.dart'; import '../../utils/pagination.dart'; import '../../widgets/custom_text_field.dart'; -class AdvancePurchase extends StatefulWidget { - const AdvancePurchase({super.key}); +class MIShotel extends StatefulWidget { + const MIShotel({super.key}); @override - _AdvancePurchaseState createState() => _AdvancePurchaseState(); + _MIShotelState createState() => _MIShotelState(); } -class _AdvancePurchaseState extends State +class _MIShotelState extends State with SingleTickerProviderStateMixin { final ApiService apiService = ApiService(); @@ -42,12 +44,12 @@ class _AdvancePurchaseState extends State int currentPage2 = 0; int itemsPerPage2 = 10; late TabController _tabController; - final List tabNames = ['Domestic', 'International']; + String selectedTabName = 'domestic'; Map focusNodes = {}; Map focusStates = {}; Map textControllers = {}; Map errorMessages = {}; - // Map advancePurchaseReport = {}; + // Map MIShotelReport = {}; List> domesticData = []; List> internationalData = []; // Map domesticData = {}; @@ -59,6 +61,7 @@ class _AdvancePurchaseState extends State void initState() { super.initState(); loadInitialData(); + _checkAuthAndLoadData(); if (!textControllers.containsKey("from_date")) { textControllers["from_date"] = TextEditingController(); } @@ -83,6 +86,9 @@ class _AdvancePurchaseState extends State _tabController.addListener(() { if (_tabController.indexIsChanging == false) { // Only fire when tab change is complete + setState(() { + selectedTabName = getTabName(_tabController.index); + }); print(" :) :X Selected Tab: ${getTabName(_tabController.index)}"); } }); @@ -97,17 +103,18 @@ class _AdvancePurchaseState extends State }); getToken(); - // fetchAdvancePurchaseReport(); + // fetchMIShotelReport(); } String getTabName(int index) { switch (index) { case 0: - return "Domestic"; + return "domestic"; case 1: - return "International"; + return "international"; default: - return "Unknown"; + // return "Unknown"; + return "domestic"; } } @@ -118,7 +125,26 @@ class _AdvancePurchaseState extends State }); }); } + void _checkAuthAndLoadData() async { + final String? token = await getToken(); // Your async function to get token + if (token == null || token.isEmpty) { + // Token doesn't exist → redirect to login + context.go( + "/", + ); // or use: router.go("/") if you're using `GoRouter` directly + return; + } + if (!mounted) return; + try { + + WidgetsBinding.instance.addPostFrameCallback((_) { + loadInitialData(); + }); + } catch (e) { + print("service report : $e"); + } + } void loadInitialData() async { String? layoutString = await getLayoutColor(); String? bodyStringColor = await getBodyColor(); @@ -190,14 +216,18 @@ class _AdvancePurchaseState extends State setState(() { domesticData = []; internationalData = []; + currentPage1 = 0; + itemsPerPage1 = 10; + currentPage2 = 0; + itemsPerPage2 = 10; }); final fromDateText = textControllers["from_date"]?.text; final toDateText = textControllers["to_date"]?.text; if (fromDateText == null || fromDateText.isEmpty || toDateText == null || toDateText.isEmpty) { - errorMessages["from_date"] = "Required"; - errorMessages["to_date"] = "Required"; + fromDateText == null || fromDateText.isEmpty ? errorMessages["from_date"] = "Required" : errorMessages.remove("from_date"); + toDateText == null || toDateText.isEmpty ? errorMessages["to_date"] = "Required" : errorMessages.remove("to_date"); setState(() {}); return; } @@ -224,13 +254,18 @@ class _AdvancePurchaseState extends State loaderFlag = true; try { final result = await apiService.CallReports( - 'advancePurchaseReport', - formattedfromDate, - formattedtoDate, + 'misHotelReport', + jsonEncode({"fromDate":'$formattedfromDate',"toDate":'$formattedtoDate'}), ); setState(() { - domesticData = List>.from(result['data']['domestic'] ?? []); - internationalData = List>.from(result['data']['international'] ?? []); + // domesticData = List>.from(result['data']['domestic'] ?? []); + domesticData = List>.from( + result['status'] == 'success' ? result['data']['domestic'] ?? [] : [] + ); + + internationalData = List>.from( + result['status'] == 'success' ? result['data']['international'] ?? [] : [] + ); loaderFlag = false; }); } catch (e) { @@ -243,6 +278,51 @@ class _AdvancePurchaseState extends State } } + + + Future handleDownload() async { + final dateFormat = DateFormat('dd-MM-yyyy'); + + if (textControllers["from_date"]!.text.isEmpty || textControllers["to_date"]!.text.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: Colors.redAccent, + content: Text("Please choose a valid date range."), + behavior: SnackBarBehavior.floating, + ), + ); + return; + } + + final DateTime fromDate = dateFormat.parse(textControllers["from_date"]!.text); + final DateTime toDate = dateFormat.parse(textControllers["to_date"]!.text); + + final formattedFromDate = DateFormat('yyyy-MM-dd').format(fromDate); + final formattedToDate = DateFormat('yyyy-MM-dd').format(toDate); + + final name = + 'MIS Hotel - $selectedTabName Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})'; + final safeName = name.replaceAll(RegExp(r'[^\w\s-]'), ''); + final excelName = '$safeName'; + + final result = await apiService.reportExcelDownload( + 'misHotelReport', + jsonEncode({ + "fromDate": formattedFromDate, + "toDate": formattedToDate, + "export": selectedTabName, + }), + excelName, + ); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: Colors.green, + content: Text(result as String), + behavior: SnackBarBehavior.floating, + ), + ); + } @override // Widget build(BuildContext context) { // // TODO: implement build @@ -274,7 +354,7 @@ class _AdvancePurchaseState extends State children: [ // if (isDesktop) CustomDrawer(isDesktop: true), // const Expanded(child: Center(child: Text("User Page Content"))), - Expanded(child: buildAdvancePurchaseLayout(isDesktop)) + Expanded(child: buildMIShotelLayout(isDesktop)) ], ), ), @@ -283,11 +363,11 @@ class _AdvancePurchaseState extends State ); } - Widget buildAdvancePurchaseLayout(bool isDesktop) { - return Container( child: buildAdvancePurchaseFormLayout(isDesktop) ); + Widget buildMIShotelLayout(bool isDesktop) { + return Container( child: buildMIShotelFormLayout(isDesktop) ); } - Widget buildAdvancePurchaseFormLayout(bool isDesktop) { + Widget buildMIShotelFormLayout(bool isDesktop) { return Container( margin: isDesktop ? EdgeInsets.all(10.0) : null, padding: const EdgeInsets.only(top: 5, bottom: 5, left: 20, right: 20), @@ -309,7 +389,7 @@ class _AdvancePurchaseState extends State mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - 'Advance Purchase', + 'Mis Hotel Report', style: GoogleFonts.poppins( fontSize: isDesktop ? 16 : 14, fontWeight: FontWeight.w600, @@ -327,9 +407,7 @@ class _AdvancePurchaseState extends State ), padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), ), - onPressed: () { - // Your Excel export logic here - }, + onPressed: handleDownload, child: Row( children: [ Text( @@ -344,33 +422,33 @@ class _AdvancePurchaseState extends State ], ), ), - SizedBox(width: 10), - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFF114D8B), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide(color: Color(0xFF114D8B), width: 2), - ), - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), - ), - onPressed: () { - // Your PDF export logic here - }, - child: Row( - children: [ - Text( - "PDF", - style: GoogleFonts.poppins( - fontSize: isDesktop ? 13 : 11, - color: Colors.white, - ), - ), - SizedBox(width: 8), - Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), - ], - ), - ), + // SizedBox(width: 10), + // ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: Color(0xFF114D8B), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8), + // side: BorderSide(color: Color(0xFF114D8B), width: 2), + // ), + // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + // ), + // onPressed: () { + // // Your PDF export logic here + // }, + // child: Row( + // children: [ + // Text( + // "PDF", + // style: GoogleFonts.poppins( + // fontSize: isDesktop ? 13 : 11, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 8), + // Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), + // ], + // ), + // ), ], ), ], @@ -519,43 +597,47 @@ class _AdvancePurchaseState extends State ], ), if (isDesktop) Spacer() else SizedBox(height: 8), - SizedBox( - child: ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFF114D8B), - foregroundColor: Colors.white, - disabledBackgroundColor: Color(0xFF114D8B), - disabledForegroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide(color: Color(0xFF114D8B), width: 2), + Padding( + padding: EdgeInsets.only(top: 10, left: 4), + child : SizedBox( + child: ElevatedButton( + + style: ElevatedButton.styleFrom( + backgroundColor: Color(0xFF114D8B), + foregroundColor: Colors.white, + disabledBackgroundColor: Color(0xFF114D8B), + disabledForegroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide(color: Color(0xFF114D8B), width: 2), + ), + padding: EdgeInsets.symmetric( + horizontal: 20, + vertical: 12, + ), ), - padding: EdgeInsets.symmetric( - horizontal: 20, - vertical: 12, - ), - ), - onPressed: () {handleSubmit();}, - child: Row( - mainAxisSize: - MainAxisSize.min, // Ensures content fits nicely - children: [ - Text( - "Search", - style: GoogleFonts.poppins( - fontSize: isDesktop ? 13 : 11, + onPressed: () {handleSubmit();}, + child: Row( + mainAxisSize: + MainAxisSize.min, // Ensures content fits nicely + children: [ + Text( + "Search", + style: GoogleFonts.poppins( + fontSize: isDesktop ? 13 : 11, + ), ), - ), - SizedBox(width: 8), // spacing between icon and text - Icon( - Icons.search, - size: 15, - color: Colors.white, - ), - ], + SizedBox(width: 8), // spacing between icon and text + Icon( + Icons.search, + size: 15, + color: Colors.white, + ), + ], + ), ), ), - ), + ) ], ), SizedBox(height: 5), @@ -616,65 +698,61 @@ class _AdvancePurchaseState extends State overflow: TextOverflow.ellipsis, // Ensures title doesn't overflow ), ), - SizedBox(width: 16), - /// Buttons on the right - Row( - children: [ - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFF114D8B), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide(color: Color(0xFF114D8B), width: 2), - ), - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), - ), - onPressed: () { - // Excel export logic - }, - child: Row( - children: [ - Text( - "Excel", - style: GoogleFonts.poppins( - fontSize: isDesktop ? 13 : 11, - color: Colors.white, - ), - ), - SizedBox(width: 8), - Icon(Icons.file_present_outlined, size: 15, color: Colors.white), - ], - ), - ), - SizedBox(width: 10), - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFF114D8B), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide(color: Color(0xFF114D8B), width: 2), - ), - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), - ), - onPressed: () { - // PDF export logic - }, - child: Row( - children: [ - Text( - "PDF", - style: GoogleFonts.poppins( - fontSize: isDesktop ? 13 : 11, - color: Colors.white, - ), - ), - SizedBox(width: 8), - Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), - ], - ), - ), - ], - ), + // SizedBox(width: 16), + // /// Buttons on the right + // Row( + // children: [ + // ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: Color(0xFF114D8B), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8), + // side: BorderSide(color: Color(0xFF114D8B), width: 2), + // ), + // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + // ), + // onPressed: handleDownload, + // child: Row( + // children: [ + // Text( + // "Excel", + // style: GoogleFonts.poppins( + // fontSize: isDesktop ? 13 : 11, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 8), + // Icon(Icons.file_present_outlined, size: 15, color: Colors.white), + // ], + // ), + // ), + // SizedBox(width: 10), + // ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: Color(0xFF114D8B), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8), + // side: BorderSide(color: Color(0xFF114D8B), width: 2), + // ), + // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + // ), + // onPressed: handleDownload, + // child: Row( + // children: [ + // Text( + // "PDF", + // style: GoogleFonts.poppins( + // fontSize: isDesktop ? 13 : 11, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 8), + // Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), + // ], + // ), + // ), + // ], + // ), ], ), ), @@ -748,26 +826,40 @@ class _AdvancePurchaseState extends State color: Colors.grey.shade200, ), ), + // rows: paginatedDomestic columns: [ DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Employee Name', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Hotel Name', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Hotel City', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Check In Date', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Check Out Date', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), ], rows: paginatedDomestic.map((entry) { + final checkInDate = DateFormat('dd-MM-yyyy').format(DateTime.parse(entry['check_in_date'])); + final checkOutDate = DateFormat('dd-MM-yyyy').format(DateTime.parse(entry['check_out_date'])); + return DataRow(cells: [ DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['employee_name']}', style: GoogleFonts.poppins(fontSize: 12))), DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['hotel_name']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['hotel_city']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text(checkInDate, style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text(checkOutDate, style: GoogleFonts.poppins(fontSize: 12))), + ]); }).toList(), + ), ), ), @@ -971,24 +1063,35 @@ class _AdvancePurchaseState extends State color: Colors.grey.shade200, ), ), + // rows: paginatedInternational columns: [ DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Employee Name', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Hotel Name', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Hotel City', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Check In Date', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + DataColumn(label: Text('Check Out Date', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), ], rows: paginatedInternational.map((entry) { + final checkInDate = DateFormat('dd-MM-yyyy').format(DateTime.parse(entry['check_in_date'])); + final checkOutDate = DateFormat('dd-MM-yyyy').format(DateTime.parse(entry['check_out_date'])); return DataRow(cells: [ DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['employee_name']}', style: GoogleFonts.poppins(fontSize: 12))), DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['hotel_name']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text('${entry['hotel_city']}', style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text(checkInDate, style: GoogleFonts.poppins(fontSize: 12))), + DataCell(Text(checkOutDate, style: GoogleFonts.poppins(fontSize: 12))), ]); }).toList(), ), diff --git a/lib/Screens/reports/reportList.dart b/lib/Screens/reports/reportList.dart index 6b29641..d5c1f0b 100644 --- a/lib/Screens/reports/reportList.dart +++ b/lib/Screens/reports/reportList.dart @@ -30,6 +30,7 @@ class _ReportListState extends State { void initState() { super.initState(); loadInitialData(); + _checkAuthAndLoadData(); } void loadInitialData() async { @@ -38,13 +39,32 @@ class _ReportListState extends State { setState(() { layoutColor = - layoutString != null - ? Color(int.parse(layoutString)) - : Colors.redAccent; - + layoutString != null + ? Color(int.parse(layoutString)) + : Colors.redAccent; }); } + void _checkAuthAndLoadData() async { + final String? token = await getToken(); // Your async function to get token + + if (token == null || token.isEmpty) { + // Token doesn't exist → redirect to login + context.go( + "/", + ); // or use: router.go("/") if you're using `GoRouter` directly + return; + } + if (!mounted) return; + try { + WidgetsBinding.instance.addPostFrameCallback((_) { + loadInitialData(); + }); + } catch (e) { + print("service report : $e"); + } + } + @override Widget build(BuildContext context) { return ResponsiveBuilder( @@ -62,16 +82,16 @@ class _ReportListState extends State { 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), + 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), @@ -97,38 +117,37 @@ class _ReportListState extends State { { 'value': '/misServicesAnalysis', 'icon': Icons.miscellaneous_services, - 'label': 'Miscellaneous Services Analysis', - 'description': 'View Miscellaneous Services Analysis', + 'label': 'MIS Services Analysis', + 'description': 'View MIS Services Analysis', }, { 'value': '/misAirReport', 'icon': Icons.flight, - 'label': 'Miscellaneous Air Report', - 'description': 'View Miscellaneous Air Report', + 'label': 'MIS Air Report', + 'description': 'View MIS Air Report', }, { 'value': '/misHotelReport', 'icon': Icons.add_business, - 'label': 'Miscellaneous Hotel Report', - 'description': 'View Miscellaneous Hotel Report', + 'label': 'MIS Hotel Report', + 'description': 'View MIS Hotel Report', }, { 'value': '/misForexReport', 'icon': Icons.credit_card, - 'label': 'Miscellaneous Forex Report', - 'description': 'View Miscellaneous Forex Report', + 'label': 'MIS Forex Report', + 'description': 'View MIS Forex Report', }, { 'value': '/guestHouseReport', - 'icon': Icons.add_home_work_sharp, + 'icon': Icons.home_work, 'label': 'Guest House Report', 'description': 'View Guest House Report', - } + }, ]; - return Container( padding: EdgeInsets.symmetric(vertical: 16, horizontal: 12), child: Column( @@ -152,73 +171,73 @@ class _ReportListState extends State { spacing: 16, runSpacing: 16, children: - menuItems.map((item) { - return SizedBox( - width: isDesktop ? 325 : double.infinity, - child: Card( - color: Colors.white, - child: InkWell( - onTap: () async { - if (item['value'] as String == - "/forexTexmplate") { - final data = - await apiService.getForexTemplate(); - print("ForexId -- $data"); + menuItems.map((item) { + return SizedBox( + width: isDesktop ? 325 : double.infinity, + child: Card( + color: Colors.white, + child: InkWell( + 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; - context.go(route); - } - }, - child: Padding( - padding: EdgeInsets.all(12), - child: Row( - children: [ - Icon( - item['icon'], - size: 40, - color: layoutColor, - // color: Color(0xFF114D8B), - ), - SizedBox(width: 16), - Expanded( - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - item['label'], - style: GoogleFonts.poppins( - fontSize: 14, - fontWeight: FontWeight.w500, - ), + context.go( + '/templateForex', + extra: {'templateData': data}, + ); + } else { + final route = item['value'] as String; + context.go(route); + } + }, + child: Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Icon( + item['icon'], + size: 40, + color: layoutColor, + // color: Color(0xFF114D8B), + ), + SizedBox(width: 16), + Expanded( + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + item['label'], + style: GoogleFonts.poppins( + fontSize: 14, + fontWeight: FontWeight.w500, + ), + ), + SizedBox(height: 4), + Text( + item['description'], + maxLines: 1, + overflow: TextOverflow.ellipsis, + softWrap: false, + style: TextStyle( + fontSize: 14, + color: Colors.grey[700], + ), + ), + ], ), - SizedBox(height: 4), - Text( - item['description'], - maxLines: 1, - overflow: TextOverflow.ellipsis, - softWrap: false, - style: TextStyle( - fontSize: 14, - color: Colors.grey[700], - ), - ), - ], - ), + ), + ], ), - ], + ), ), ), - ), - ), - ); - }).toList(), + ); + }).toList(), ), ), ), diff --git a/lib/Screens/reports/servicesAnalysis.dart b/lib/Screens/reports/servicesAnalysis.dart index 29e73c1..7bfb25b 100644 --- a/lib/Screens/reports/servicesAnalysis.dart +++ b/lib/Screens/reports/servicesAnalysis.dart @@ -1,5 +1,7 @@ import 'dart:convert'; import 'dart:core'; +import 'dart:typed_data'; + import 'package:go_router/go_router.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; @@ -8,12 +10,13 @@ import 'package:frontend/config/apiUrl.dart'; import 'package:intl/intl.dart'; import 'package:responsive_builder/responsive_builder.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:universal_html/html.dart' as html; import '../../routes/custom_appBar.dart'; import '../../routes/custom_drawer.dart'; -import '../../routes/mainLayout.dart'; import '../../services/apiService.dart'; import '../../utils/auth_utils.dart'; +import '../../utils/pagination.dart'; import '../../widgets/custom_text_field.dart'; class ServicesAnalysis extends StatefulWidget { @@ -23,7 +26,8 @@ class ServicesAnalysis extends StatefulWidget { _ServicesAnalysisState createState() => _ServicesAnalysisState(); } -class _ServicesAnalysisState extends State { +class _ServicesAnalysisState extends State + with SingleTickerProviderStateMixin { final ApiService apiService = ApiService(); String? userId; @@ -34,20 +38,29 @@ class _ServicesAnalysisState extends State { Color? layoutColor; Color? bodyColor; + int currentPage1 = 0; + int itemsPerPage1 = 10; + int currentPage2 = 0; + int itemsPerPage2 = 10; + late TabController _tabController; + String selectedTabName = 'domestic'; Map focusNodes = {}; Map focusStates = {}; Map textControllers = {}; Map errorMessages = {}; // Map ServicesAnalysisReport = {}; List> domesticData = []; - List> internationData = []; + List> internationalData = []; // Map domesticData = {}; - // Map internationData = {}; + // Map internationalData = {}; + + bool loaderFlag = false; @override void initState() { super.initState(); - + loadInitialData(); + _checkAuthAndLoadData(); if (!textControllers.containsKey("from_date")) { textControllers["from_date"] = TextEditingController(); } @@ -67,7 +80,17 @@ class _ServicesAnalysisState extends State { focusStates["from_date"] = false; } + _tabController = TabController(length: 2, vsync: this); + _tabController.addListener(() { + if (_tabController.indexIsChanging == false) { + // Only fire when tab change is complete + setState(() { + selectedTabName = getTabName(_tabController.index); + }); + print(" :) :X Selected Tab: ${getTabName(_tabController.index)}"); + } + }); // Add focus listeners focusNodes.forEach((key, focusNode) { @@ -81,6 +104,19 @@ class _ServicesAnalysisState extends State { getToken(); // fetchServicesAnalysisReport(); } + + String getTabName(int index) { + switch (index) { + case 0: + return "domestic"; + case 1: + return "international"; + default: + // return "Unknown"; + return "domestic"; + } + } + void _addFocusListener(FocusNode node, Function(bool) updateState) { node.addListener(() { setState(() { @@ -94,13 +130,16 @@ class _ServicesAnalysisState extends State { String? bodyStringColor = await getBodyColor(); setState(() { - layoutColor = layoutString != null ? Color(int.parse(layoutString)) - : Colors.redAccent; + layoutColor = + layoutString != null + ? Color(int.parse(layoutString)) + : Colors.redAccent; - bodyColor = bodyStringColor != null ? Color(int.parse(bodyStringColor)) - : Colors.white; + bodyColor = + bodyStringColor != null + ? Color(int.parse(bodyStringColor)) + : Colors.white; }); - } Future initializeData() async { @@ -109,13 +148,31 @@ class _ServicesAnalysisState extends State { orgId = await getOrgId(); roleUser = await getRoleUser(); - if (token == null || userId == null) { print("Token or USerId missing"); return; } } + void _checkAuthAndLoadData() async { + final String? token = await getToken(); // Your async function to get token + + if (token == null || token.isEmpty) { + // Token doesn't exist → redirect to login + context.go( + "/", + ); // or use: router.go("/") if you're using `GoRouter` directly + return; + } + if (!mounted) return; + try { + WidgetsBinding.instance.addPostFrameCallback((_) { + loadInitialData(); + }); + } catch (e) { + print("service report : $e"); + } + } Future getUserId() async { final prefs = await SharedPreferences.getInstance(); @@ -152,18 +209,30 @@ class _ServicesAnalysisState extends State { return prefs.getString('auth_token'); } - Future handleSubmit() async { errorMessages.remove("from_date"); errorMessages.remove("to_date"); - + setState(() { + domesticData = []; + internationalData = []; + currentPage1 = 0; + itemsPerPage1 = 10; + currentPage2 = 0; + itemsPerPage2 = 10; + }); final fromDateText = textControllers["from_date"]?.text; final toDateText = textControllers["to_date"]?.text; - if (fromDateText == null || fromDateText.isEmpty || - toDateText == null || toDateText.isEmpty) { - errorMessages["from_date"] = "Required"; - errorMessages["to_date"] = "Required"; + if (fromDateText == null || + fromDateText.isEmpty || + toDateText == null || + toDateText.isEmpty) { + fromDateText == null || fromDateText.isEmpty + ? errorMessages["from_date"] = "Required" + : errorMessages.remove("from_date"); + toDateText == null || toDateText.isEmpty + ? errorMessages["to_date"] = "Required" + : errorMessages.remove("to_date"); setState(() {}); return; } @@ -179,22 +248,92 @@ class _ServicesAnalysisState extends State { setState(() {}); return; } + setState(() { + loaderFlag = true; + }); // Format for API request final formattedfromDate = DateFormat('yyyy-MM-dd').format(fromDate); final formattedtoDate = DateFormat('yyyy-MM-dd').format(toDate); // Fetch and update - final result = await apiService.CallReports( + + loaderFlag = true; + try { + final result = await apiService.CallReports( + 'misServicesAnalysis', + jsonEncode({ + "fromDate": '$formattedfromDate', + "toDate": '$formattedtoDate', + }), + ); + setState(() { + domesticData = List>.from( + result['status'] == 'success' ? result['data']['domestic'] ?? [] : [], + ); + + internationalData = List>.from( + result['status'] == 'success' + ? result['data']['international'] ?? [] + : [], + ); + loaderFlag = false; + }); + } catch (e) { + // handle error + setState(() { + loaderFlag = false; + domesticData = []; + internationalData = []; + }); + } + } + + Future handleDownload() async { + final dateFormat = DateFormat('dd-MM-yyyy'); + + if (textControllers["from_date"]!.text.isEmpty || + textControllers["to_date"]!.text.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: Colors.redAccent, + content: Text("Please choose a valid date range."), + behavior: SnackBarBehavior.floating, + ), + ); + return; + } + + final DateTime fromDate = dateFormat.parse( + textControllers["from_date"]!.text, + ); + final DateTime toDate = dateFormat.parse(textControllers["to_date"]!.text); + + final formattedFromDate = DateFormat('yyyy-MM-dd').format(fromDate); + final formattedToDate = DateFormat('yyyy-MM-dd').format(toDate); + + final name = + 'MIS Services Analysis - $selectedTabName Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})'; + final safeName = name.replaceAll(RegExp(r'[^\w\s-]'), ''); + final excelName = '$safeName'; + + final result = await apiService.reportExcelDownload( 'misServicesAnalysis', - formattedfromDate, - formattedtoDate, + jsonEncode({ + "fromDate": formattedFromDate, + "toDate": formattedToDate, + "export": selectedTabName, + }), + excelName, ); - setState(() { - domesticData = List>.from(result['data']['domestic'] ?? []); - internationData = List>.from(result['data']['international'] ?? []); - }); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: Colors.green, + content: Text(result as String), + behavior: SnackBarBehavior.floating, + ), + ); } @override @@ -202,11 +341,11 @@ class _ServicesAnalysisState extends State { // // TODO: implement build // throw UnimplementedError(); // } - Widget build(BuildContext context) { return ResponsiveBuilder( builder: (context, sizingInfo) { - bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop; + bool isDesktop = + sizingInfo.deviceScreenType == DeviceScreenType.desktop; return Scaffold( backgroundColor: Color(0xFFf5f5f5), @@ -214,21 +353,21 @@ class _ServicesAnalysisState extends State { 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), + 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), // const Expanded(child: Center(child: Text("User Page Content"))), - Expanded(child: buildServicesAnalysisLayout(isDesktop)) + Expanded(child: buildServicesAnalysisLayout(isDesktop)), ], ), ), @@ -238,20 +377,20 @@ class _ServicesAnalysisState extends State { } Widget buildServicesAnalysisLayout(bool isDesktop) { - return Container( child: buildServicesAnalysisFormLayout(isDesktop) ); + return Container(child: buildServicesAnalysisFormLayout(isDesktop)); } Widget buildServicesAnalysisFormLayout(bool isDesktop) { return Container( margin: isDesktop ? EdgeInsets.all(10.0) : null, - padding: const EdgeInsets.only(top: 15, bottom: 15, left: 20, right: 20), - height: isDesktop - ? MediaQuery.of(context).size.height * 0.98 - : MediaQuery.of(context).size.height, + padding: const EdgeInsets.only(top: 5, bottom: 5, left: 20, right: 20), + // color: Colors.brown, + height: + isDesktop + ? MediaQuery.of(context).size.height * 1 + : MediaQuery.of(context).size.height, decoration: BoxDecoration( - border: isDesktop - ? Border.all(width: 2, color: Colors.white) - : null, + border: isDesktop ? Border.all(width: 2, color: Colors.white) : null, color: isDesktop ? Colors.white : Color(0xFFFCFCFC), ), child: Column( @@ -262,7 +401,7 @@ class _ServicesAnalysisState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - 'Miscellaneous Services Analysis', + 'Service Analysis Report', style: GoogleFonts.poppins( fontSize: isDesktop ? 16 : 14, fontWeight: FontWeight.w600, @@ -278,11 +417,12 @@ class _ServicesAnalysisState extends State { borderRadius: BorderRadius.circular(8), side: BorderSide(color: Color(0xFF114D8B), width: 2), ), - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + padding: EdgeInsets.symmetric( + horizontal: 20, + vertical: 12, + ), ), - onPressed: () { - // Your Excel export logic here - }, + onPressed: handleDownload, child: Row( children: [ Text( @@ -293,34 +433,11 @@ class _ServicesAnalysisState extends State { ), ), SizedBox(width: 8), - Icon(Icons.file_present_outlined, size: 15, color: Colors.white), - ], - ), - ), - SizedBox(width: 10), - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFF114D8B), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide(color: Color(0xFF114D8B), width: 2), - ), - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), - ), - onPressed: () { - // Your PDF export logic here - }, - child: Row( - children: [ - Text( - "PDF", - style: GoogleFonts.poppins( - fontSize: isDesktop ? 13 : 11, - color: Colors.white, - ), + Icon( + Icons.file_present_outlined, + size: 15, + color: Colors.white, ), - SizedBox(width: 8), - Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), ], ), ), @@ -328,7 +445,7 @@ class _ServicesAnalysisState extends State { ), ], ), - SizedBox(height: 15), + SizedBox(height: 5), // ------------------- Second Row ------------------- Row( @@ -359,8 +476,9 @@ class _ServicesAnalysisState extends State { lastDate: DateTime(2100), ); if (pickedDate != null) { - textControllers["from_date"]?.text = - DateFormat('dd-MM-yyyy').format(pickedDate); + textControllers["from_date"]?.text = DateFormat( + 'dd-MM-yyyy', + ).format(pickedDate); } }, child: AbsorbPointer( @@ -375,9 +493,12 @@ class _ServicesAnalysisState extends State { fontSize: 12, color: Colors.grey, ), - floatingLabelBehavior: FloatingLabelBehavior.never, + floatingLabelBehavior: + FloatingLabelBehavior.never, border: InputBorder.none, - contentPadding: const EdgeInsets.symmetric(vertical: 16), + contentPadding: const EdgeInsets.symmetric( + vertical: 16, + ), suffixIcon: const Icon( Icons.calendar_today, size: 16, @@ -418,10 +539,13 @@ class _ServicesAnalysisState extends State { height: 40, child: GestureDetector( onTap: () async { - final fromDateText = textControllers["from_date"]?.text; + final fromDateText = + textControllers["from_date"]?.text; DateTime? mintoDate; if (fromDateText != null && fromDateText.isNotEmpty) { - mintoDate = DateFormat('dd-MM-yyyy').parse(fromDateText); + mintoDate = DateFormat( + 'dd-MM-yyyy', + ).parse(fromDateText); } final pickedDate = await showDatePicker( @@ -432,8 +556,9 @@ class _ServicesAnalysisState extends State { ); if (pickedDate != null) { - textControllers["to_date"]?.text = - DateFormat('dd-MM-yyyy').format(pickedDate); + textControllers["to_date"]?.text = DateFormat( + 'dd-MM-yyyy', + ).format(pickedDate); } }, child: AbsorbPointer( @@ -444,10 +569,16 @@ class _ServicesAnalysisState extends State { style: const TextStyle(fontSize: 12), decoration: const InputDecoration( labelText: "Select Date", - labelStyle: TextStyle(fontSize: 12, color: Colors.grey), - floatingLabelBehavior: FloatingLabelBehavior.never, + labelStyle: TextStyle( + fontSize: 12, + color: Colors.grey, + ), + floatingLabelBehavior: + FloatingLabelBehavior.never, border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(vertical: 16), + contentPadding: EdgeInsets.symmetric( + vertical: 16, + ), suffixIcon: Icon( Icons.calendar_today, size: 16, @@ -466,52 +597,54 @@ class _ServicesAnalysisState extends State { style: const TextStyle(color: Colors.red, fontSize: 12), maxLines: 2, // Allow it to wrap onto two lines overflow: - TextOverflow.ellipsis, // Add ellipsis if it still overflows + TextOverflow + .ellipsis, // Add ellipsis if it still overflows ), ], ], ), if (isDesktop) Spacer() else SizedBox(height: 8), - SizedBox( - child: ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFF114D8B), - foregroundColor: Colors.white, - disabledBackgroundColor: Color(0xFF114D8B), - disabledForegroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide(color: Color(0xFF114D8B), width: 2), + Padding( + padding: EdgeInsets.only(top: 10, left: 4), + child: SizedBox( + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Color(0xFF114D8B), + foregroundColor: Colors.white, + disabledBackgroundColor: Color(0xFF114D8B), + disabledForegroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide(color: Color(0xFF114D8B), width: 2), + ), + padding: EdgeInsets.symmetric( + horizontal: 20, + vertical: 12, + ), ), - padding: EdgeInsets.symmetric( - horizontal: 20, - vertical: 12, - ), - ), - onPressed: () {handleSubmit();}, - child: Row( - mainAxisSize: - MainAxisSize.min, // Ensures content fits nicely - children: [ - Text( - "Search", - style: GoogleFonts.poppins( - fontSize: isDesktop ? 13 : 11, + onPressed: () { + handleSubmit(); + }, + child: Row( + mainAxisSize: + MainAxisSize.min, // Ensures content fits nicely + children: [ + Text( + "Search", + style: GoogleFonts.poppins( + fontSize: isDesktop ? 13 : 11, + ), ), - ), - SizedBox(width: 8), // spacing between icon and text - Icon( - Icons.search, - size: 15, - color: Colors.white, - ), - ], + SizedBox(width: 8), // spacing between icon and text + Icon(Icons.search, size: 15, color: Colors.white), + ], + ), ), ), ), ], ), - SizedBox(height: 15), + SizedBox(height: 5), // ------------------- Third Row ------------------- DefaultTabController( @@ -519,148 +652,620 @@ class _ServicesAnalysisState extends State { child: Column( children: [ TabBar( + controller: _tabController, labelColor: Colors.black, unselectedLabelColor: Colors.grey, indicatorColor: Color(0xFF114D8B), - tabs: [ - Tab(text: "Domestic"), - Tab(text: "International"), - ], + tabs: [Tab(text: "Domestic"), Tab(text: "International")], ), - SizedBox(height: 10), + SizedBox(height: 5), Container( - height: 200, // Or use Expanded for flexible height + // color:Colors.grey, + height: MediaQuery.of(context).size.height * 0.6, + // height: 200, // Or use Expanded for flexible height child: TabBarView( + controller: _tabController, children: [ - // Domestic Tab - domesticData.isEmpty + loaderFlag + ? Center(child: CircularProgressIndicator()) + : domesticData.isEmpty ? Center( - child: Padding( - padding: EdgeInsets.all(16), - child: Text( - "No data found", - style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w500), - ), - ), - ) - : Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), - child: Text( - "Domestic Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", - style: GoogleFonts.poppins(fontSize: 13, fontWeight: FontWeight.w500, color: Colors.grey[700]), - ), - ), - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: DataTable( - dividerThickness: 0.5, - columnSpacing: isDesktop ? 24.0 : 16.0, - border: TableBorder( - horizontalInside: BorderSide( - width: 0.5, - color: Colors.grey.shade200, - ), + child: Padding( + padding: EdgeInsets.all(16), + child: Text( + "No data found", + style: GoogleFonts.poppins( + fontSize: 14, + fontWeight: FontWeight.w500, ), - columns: [ - DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - ], - rows: domesticData.map((entry) { - return DataRow(cells: [ - DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), - ]); - }).toList(), ), ), + ) + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, + vertical: 8, + ), + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + /// Title on the left + Expanded( + child: Text( + "Domestic Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", + style: GoogleFonts.poppins( + fontSize: 13, + fontWeight: FontWeight.w500, + color: Colors.grey[700], + ), + overflow: + TextOverflow + .ellipsis, // Ensures title doesn't overflow + ), + ), + // SizedBox(width: 16), + // /// Buttons on the right + // Row( + // children: [ + // ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: Color(0xFF114D8B), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8), + // side: BorderSide(color: Color(0xFF114D8B), width: 2), + // ), + // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + // ), + // onPressed: handleDownload, + // child: Row( + // children: [ + // Text( + // "Excel", + // style: GoogleFonts.poppins( + // fontSize: isDesktop ? 13 : 11, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 8), + // Icon(Icons.file_present_outlined, size: 15, color: Colors.white), + // ], + // ), + // ), + // SizedBox(width: 10), + // ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: Color(0xFF114D8B), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8), + // side: BorderSide(color: Color(0xFF114D8B), width: 2), + // ), + // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + // ), + // onPressed: handleDownload, + // child: Row( + // children: [ + // Text( + // "PDF", + // style: GoogleFonts.poppins( + // fontSize: isDesktop ? 13 : 11, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 8), + // Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), + // ], + // ), + // ), + // ], + // ), + ], + ), + ), + + /* For pagination for list ... */ + // Expanded( + // child: SingleChildScrollView( + // scrollDirection: Axis.horizontal, + // child: SingleChildScrollView( + // scrollDirection: Axis.vertical, + // child: DataTable( + // dividerThickness: 0.5, + // columnSpacing: isDesktop ? 30.0 : 24.0, + // border: TableBorder( + // horizontalInside: BorderSide( + // width: 0.5, + // color: Colors.grey.shade200, + // ), + // ), + // columns: [ + // DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // ], + // rows: domesticData.map((entry) { + // return DataRow(cells: [ + // DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), + // ]); + // }).toList(), + // ), + // ), + // ), + // ), + // -------- Table with Pagination -------- + Expanded( + child: LayoutBuilder( + builder: (context, constraints) { + final double minWidth = + isDesktop ? constraints.maxWidth : 1300; + + // Pagination logic + List> + paginatedDomestic = + domesticData + .skip(currentPage1 * itemsPerPage1) + .take(itemsPerPage1) + .toList(); + + return Column( + children: [ + Expanded( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: ConstrainedBox( + constraints: BoxConstraints( + minWidth: minWidth, + ), + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: DataTable( + dividerThickness: 0.5, + columnSpacing: + isDesktop ? 30.0 : 24.0, + border: TableBorder( + horizontalInside: + BorderSide( + width: 0.5, + color: + Colors + .grey + .shade200, + ), + ), + columns: [ + DataColumn( + label: Text( + 'Service', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Count', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Plan Trip Type', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + ], + rows: + paginatedDomestic.map(( + entry, + ) { + return DataRow( + cells: [ + DataCell( + Text( + '${entry['Service']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['flight_service_count']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['plan_trip_type']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + ], + ); + }).toList(), + ), + ), + ), + ), + ), + + // Pagination controls + PaginationControls( + currentPage: currentPage1, + itemsPerPage: itemsPerPage1, + totalItems: domesticData.length, + activeColor: layoutColor, + onPageChanged: (page) { + setState(() { + currentPage1 = page; + }); + }, + onItemsPerPageChanged: (items) { + setState(() { + itemsPerPage1 = items; + currentPage1 = 0; + }); + }, + ), + ], + ); + }, + ), + ), + ], ), - ], - ), // International Tab - internationData.isEmpty + internationalData.isEmpty ? Center( - child: Padding( - padding: EdgeInsets.all(16), - child: Text( - "No data found", - style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w500), - ), - ), - ) - : Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), - child: Text( - "International Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", - style: GoogleFonts.poppins(fontSize: 13, fontWeight: FontWeight.w500, color: Colors.grey[700]), - ), - ), - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: DataTable( - dividerThickness: 0.5, - columnSpacing: isDesktop ? 24.0 : 16.0, - border: TableBorder( - horizontalInside: BorderSide( - width: 0.5, - color: Colors.grey.shade200, - ), + child: Padding( + padding: EdgeInsets.all(16), + child: Text( + "No data found", + style: GoogleFonts.poppins( + fontSize: 14, + fontWeight: FontWeight.w500, ), - columns: [ - DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), - ], - rows: internationData.map((entry) { - return DataRow(cells: [ - DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), - DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), - ]); - }).toList(), ), ), + ) + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Padding( + // padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), + // child: Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // crossAxisAlignment: CrossAxisAlignment.center, + // children: [ + // /// Title on the left + // Expanded( + // child: Text( + // "International Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", + // style: GoogleFonts.poppins( + // fontSize: 13, + // fontWeight: FontWeight.w500, + // color: Colors.grey[700], + // ), + // overflow: TextOverflow.ellipsis, // Ensures title doesn't overflow + // ), + // ), + // SizedBox(width: 16), + // /// Buttons on the right + // Row( + // children: [ + // ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: Color(0xFF114D8B), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8), + // side: BorderSide(color: Color(0xFF114D8B), width: 2), + // ), + // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + // ), + // onPressed: () { + // // Excel export logic + // }, + // child: Row( + // children: [ + // Text( + // "Excel", + // style: GoogleFonts.poppins( + // fontSize: isDesktop ? 13 : 11, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 8), + // Icon(Icons.file_present_outlined, size: 15, color: Colors.white), + // ], + // ), + // ), + // SizedBox(width: 10), + // ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: Color(0xFF114D8B), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8), + // side: BorderSide(color: Color(0xFF114D8B), width: 2), + // ), + // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + // ), + // onPressed: () { + // // PDF export logic + // }, + // child: Row( + // children: [ + // Text( + // "PDF", + // style: GoogleFonts.poppins( + // fontSize: isDesktop ? 13 : 11, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 8), + // Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), + // ], + // ), + // ), + // ], + // ), + // ], + // ), + // ), + // Expanded( + // child: SingleChildScrollView( + // scrollDirection: Axis.horizontal, + // child: SingleChildScrollView( + // scrollDirection: Axis.vertical, + // child: DataTable( + // dividerThickness: 0.5, + // columnSpacing: isDesktop ? 24.0 : 16.0, + // border: TableBorder( + // horizontalInside: BorderSide( + // width: 0.5, + // color: Colors.grey.shade200, + // ), + // ), + // columns: [ + // DataColumn(label: Text('Plan Id', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Employee Code', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('SO Number', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Department', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Flight Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Plan Trip Type', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Sector', style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600))), + // ], + // rows: internationalData.map((entry) { + // return DataRow(cells: [ + // DataCell(Text('${entry['plan_id']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['employee_code']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['so_number']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['functional_department']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['flight_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['plan_trip_type']}', style: GoogleFonts.poppins(fontSize: 12))), + // DataCell(Text('${entry['sector']}', style: GoogleFonts.poppins(fontSize: 12))), + // ]); + // }).toList(), + // ), + // ), + // ), + // ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, + vertical: 8, + ), + child: Text( + "International Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", + style: GoogleFonts.poppins( + fontSize: 13, + fontWeight: FontWeight.w500, + color: Colors.grey[700], + ), + ), + ), + Container( + height: + isDesktop + ? MediaQuery.of(context).size.height * + 0.51 + : 200, + // color:Colors.amberAccent, + child: LayoutBuilder( + builder: (context, constraints) { + final double minWidth = + isDesktop ? constraints.maxWidth : 1300; + + // Pagination logic + List> + paginatedInternational = + internationalData + .skip(currentPage2 * itemsPerPage2) + .take(itemsPerPage2) + .toList(); + + return Column( + children: [ + Expanded( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: ConstrainedBox( + constraints: BoxConstraints( + minWidth: minWidth, + ), + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: DataTable( + dividerThickness: 0.5, + columnSpacing: + isDesktop ? 30.0 : 24.0, + border: TableBorder( + horizontalInside: + BorderSide( + width: 0.5, + color: + Colors + .grey + .shade200, + ), + ), + columns: [ + DataColumn( + label: Text( + 'Service', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Count', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + DataColumn( + label: Text( + 'Plan Trip Type', + style: + GoogleFonts.poppins( + fontSize: 12, + fontWeight: + FontWeight + .w600, + ), + ), + ), + ], + rows: + paginatedInternational.map(( + entry, + ) { + return DataRow( + cells: [ + DataCell( + Text( + '${entry['Service']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['flight_service_count']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + DataCell( + Text( + '${entry['plan_trip_type']}', + style: + GoogleFonts.poppins( + fontSize: + 12, + ), + ), + ), + ], + ); + }).toList(), + ), + ), + ), + ), + ), + + // Pagination controls + PaginationControls( + currentPage: currentPage2, + itemsPerPage: itemsPerPage2, + totalItems: internationalData.length, + activeColor: layoutColor, + onPageChanged: (page) { + setState(() { + currentPage2 = page; + }); + }, + onItemsPerPageChanged: (items) { + setState(() { + itemsPerPage2 = items; + currentPage2 = 0; + }); + }, + ), + ], + ); + }, + ), + ), + ], ), - ], - ), ], ), ), ], ), ), - SizedBox(height: 15), - + // SizedBox(height: 15), ], ), ); } - } - diff --git a/lib/config/apiUrl.dart b/lib/config/apiUrl.dart index 7139bea..eb751b8 100644 --- a/lib/config/apiUrl.dart +++ b/lib/config/apiUrl.dart @@ -1,3 +1,3 @@ //api url -// const String apiUrl = 'http://apitest.tripapprovaltool.com/tstat_be'; -const String apiUrl = 'https://uat.tripapprovaltool.com/tstat_be'; +const String apiUrl = 'http://apitest.tripapprovaltool.com/tstat_be'; +// const String apiUrl = 'https://uat.tripapprovaltool.com/tstat_be'; diff --git a/lib/routes/custom_appBar.dart b/lib/routes/custom_appBar.dart index 8788709..dee8c99 100644 --- a/lib/routes/custom_appBar.dart +++ b/lib/routes/custom_appBar.dart @@ -632,11 +632,11 @@ final List> menuItems = [ // 'label': 'Template List' // }, // {'value': '/template', 'icon': Icons.ac_unit_sharp, 'label': 'Template'}, - // { - // 'value': '/report', - // 'icon': Icons.auto_graph, - // 'label': 'Reports', - // }, + { + 'value': '/report', + 'icon': Icons.auto_graph, + 'label': 'Reports', + }, { 'value': '/CreateUserDetails', 'icon': Icons.account_circle, diff --git a/lib/routes/custom_router.dart b/lib/routes/custom_router.dart index 8eba2f5..5e72184 100644 --- a/lib/routes/custom_router.dart +++ b/lib/routes/custom_router.dart @@ -35,9 +35,9 @@ import '../Screens/traveller/travellerList.dart'; import '../Screens/reports/reportList.dart'; import '../Screens/reports/advancePurchase.dart'; import '../Screens/reports/servicesAnalysis.dart'; -import '../Screens/reports/miscellaneousAir.dart'; -import '../Screens/reports/miscellaneousHotel.dart'; -import '../Screens/reports/miscellaneousForex.dart'; +import '../Screens/reports/misAir.dart'; +import '../Screens/reports/misHotel.dart'; +import '../Screens/reports/misForex.dart'; import '../Screens/reports/guestHouse.dart'; import 'mainLayout.dart'; @@ -164,15 +164,15 @@ final GoRouter router = GoRouter( ), GoRoute( path: '/misAirReport', - builder: (context, state) => MiscellaneousAir(), + builder: (context, state) => MISair(), ), GoRoute( path: '/misHotelReport', - builder: (context, state) => MiscellaneousHotel(), + builder: (context, state) => MIShotel(), ), GoRoute( path: '/misForexReport', - builder: (context, state) => MiscellaneousForex(), + builder: (context, state) => MISforex(), ), GoRoute( path: '/guestHouseReport', diff --git a/lib/services/apiService.dart b/lib/services/apiService.dart index ea20516..4d88d2c 100644 --- a/lib/services/apiService.dart +++ b/lib/services/apiService.dart @@ -1511,11 +1511,9 @@ class ApiService { // ----------------------- User Management - CheckDuplicate end here ---------------------------------- // ----------------------- Report ------------------------- - Future> CallReports(String apiRoute,String FromDate,String ToDate) async { + Future> CallReports(String apiRoute,String body) async { String apiUrldata = '$apiUrl/api/$apiRoute'; final token = await getToken(); - final body = jsonEncode({"fromDate":'$FromDate',"toDate":'$ToDate'}); - if (token == null) { throw Exception('Token not found. Please log in.'); @@ -1536,9 +1534,58 @@ class ApiService { } } else { throw Exception( - 'Failed to load checkDuplicate data. Status code: ${response.statusCode}', + 'Failed to load data. Status code: ${response.statusCode}', ); } } - // ----------------------- Report ------------------------- + + Future reportExcelDownload(String apiRoute,String body,String name) async { + final String apiUrldata = '$apiUrl/api/$apiRoute'; + + // Sanitize name for filename (optional) + final safeName = name.replaceAll(RegExp(r'[^\w\s-]'), ''); // remove any special chars if needed + final excelName = '$safeName.xlsx'; + + + final token = await getToken(); + + if (token == null) { + throw Exception('Token not found. Please log in.'); + } + + final response = await http.post( + Uri.parse(apiUrldata), + headers: {'Authorization': 'Bearer $token','Content-Type': 'application/json'}, + body: body + ); + + if (response.statusCode == 200) { + try { + print("report XL Dowloaded"); + print(excelName); + // Create a blob from the response body + final blob = html.Blob([response.bodyBytes]); + + // Generate a download URL for the blob + final url = html.Url.createObjectUrlFromBlob(blob); + + // Create a link element to trigger the download + final anchor = + html.AnchorElement(href: url) + ..setAttribute('download', excelName) + ..click(); + + // Revoke the download URL to free up resources + html.Url.revokeObjectUrl(url); + throw Exception('Sucessfully Downloaded'); + } catch (e) { + throw Exception('Error parsing response: $e'); + } + } else if (response.statusCode == 404) { + throw Exception('File not found.'); + } else { + throw Exception('Failed to Download'); + } + } +// ----------------------- Report ------------------------- }