import 'package:flutter/material.dart'; import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:get/get.dart'; import 'package:marco/helpers/theme/app_theme.dart'; import 'package:marco/helpers/utils/mixins/ui_mixin.dart'; import 'package:marco/helpers/utils/my_shadow.dart'; import 'package:marco/helpers/widgets/my_breadcrumb.dart'; import 'package:marco/helpers/widgets/my_breadcrumb_item.dart'; import 'package:marco/helpers/widgets/my_card.dart'; import 'package:marco/helpers/widgets/my_container.dart'; import 'package:marco/helpers/widgets/my_flex.dart'; import 'package:marco/helpers/widgets/my_flex_item.dart'; import 'package:marco/helpers/widgets/my_list_extension.dart'; import 'package:marco/helpers/widgets/my_spacing.dart'; import 'package:marco/helpers/widgets/my_text.dart'; import 'package:marco/view/layouts/layout.dart'; import 'package:marco/controller/dashboard/attendance_screen_controller.dart'; import 'package:intl/intl.dart'; class AttendanceScreen extends StatefulWidget { const AttendanceScreen({super.key}); @override State createState() => _AttendanceScreenState(); } class _AttendanceScreenState extends State with UIMixin { AttendanceController attendanceController = Get.put(AttendanceController()); @override Widget build(BuildContext context) { return Layout( child: GetBuilder( init: attendanceController, tag: 'attendance_dashboard_controller', builder: (controller) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: MySpacing.x(flexSpacing), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ MyText.titleMedium("Attendance", fontSize: 18, fontWeight: 600), MyBreadcrumb( children: [ MyBreadcrumbItem(name: 'Dashboard'), MyBreadcrumbItem(name: 'Attendance', active: true), ], ), ], ), ), MySpacing.height(flexSpacing), Padding( padding: MySpacing.x(flexSpacing / 2), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ MySpacing.height(flexSpacing), // Move project selection here Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: MyContainer.bordered( padding: MySpacing.xy(4, 8), child: PopupMenuButton( onSelected: (value) { setState(() { attendanceController.selectedProjectId = value; attendanceController .fetchEmployeesByProject(value); attendanceController .fetchAttendanceLogs(value); attendanceController .fetchAttendanceLogs(value); }); }, itemBuilder: (BuildContext context) { if (attendanceController.projects.isEmpty) { return [ PopupMenuItem( value: '', child: MyText.bodySmall('No Data', fontWeight: 600), ) ]; } return attendanceController.projects .map((project) { return PopupMenuItem( value: project.id.toString(), height: 32, child: MyText.bodySmall( project.name, color: theme.colorScheme.onSurface, fontWeight: 600, ), ); }).toList(); }, color: theme.cardTheme.color, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ MyText.labelSmall( attendanceController.selectedProjectId != null ? attendanceController.projects .firstWhereOrNull((proj) => proj.id.toString() == attendanceController .selectedProjectId) ?.name ?? 'Select a Project' : 'Select a Project', color: theme.colorScheme.onSurface, ), Icon(LucideIcons.chevron_down, size: 16, color: theme.colorScheme.onSurface), ], ), ), ), ), ], ), MySpacing.height(flexSpacing), MyFlex( children: [ MyFlexItem( child: DefaultTabController( length: 3, child: MyCard.bordered( borderRadiusAll: 4, border: Border.all(color: Colors.grey.withAlpha(50)), shadow: MyShadow( elevation: 1, position: MyShadowPosition.bottom), paddingAll: 10, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ TabBar( labelColor: theme.colorScheme.primary, unselectedLabelColor: theme .colorScheme.onSurface .withAlpha(150), tabs: const [ Tab(text: 'Employee List'), Tab(text: 'Logs'), Tab(text: 'Regularization'), ], ), MySpacing.height(16), SizedBox( height: 500, child: TabBarView( children: [ employeeListTab(), reportsTab(context), regularizationTab(context), ], ), ), ], ), ), ), ), ], ), ], ), ), ], ); }, ), ); } Widget employeeListTab() { if (attendanceController.employees.isEmpty) { return Center( child: MyText.bodySmall("No Employees Found", fontWeight: 600), ); } return SingleChildScrollView( scrollDirection: Axis.horizontal, child: DataTable( sortAscending: true, columnSpacing: 15, headingRowColor: WidgetStatePropertyAll(contentTheme.primary.withAlpha(40)), dataRowMaxHeight: 60, showBottomBorder: true, clipBehavior: Clip.antiAliasWithSaveLayer, border: TableBorder.all( borderRadius: BorderRadius.circular(4), style: BorderStyle.solid, width: 0.4, color: Colors.grey, ), columns: [ DataColumn( label: MyText.labelLarge('Name', color: contentTheme.primary)), DataColumn( label: MyText.labelLarge('Designation', color: contentTheme.primary)), DataColumn( label: MyText.labelLarge('Actions', color: contentTheme.primary)), ], rows: attendanceController.employees .mapIndexed((index, employee) => DataRow(cells: [ DataCell(MyText.bodyMedium(employee.name, fontWeight: 600)), DataCell( MyText.bodyMedium(employee.designation, fontWeight: 600)), DataCell( ElevatedButton( onPressed: () async { final success = await attendanceController .captureAndUploadAttendance( employee.id, int.parse( attendanceController.selectedProjectId ?? "0"), comment: "Checked in via app", ); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( success ? 'Attendence Marked successfully!' : 'Image upload failed.', ), ), ); }, child: const Text('Check In'), ), ), ])) .toList(), ), ); } Widget reportsTab(BuildContext context) { final attendanceController = Get.find(); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.all(8.0), child: TextButton.icon( icon: Icon(Icons.date_range), label: Text("Select Date Range for Attendance"), onPressed: () => attendanceController.selectDateRangeForAttendance( context, attendanceController), ), ), if (attendanceController.attendanceLogs.isEmpty) Expanded( child: Center( child: MyText.bodySmall("No Attendance Records Found", fontWeight: 600), ), ) else Expanded( child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: DataTable( sortAscending: true, columnSpacing: 15, headingRowColor: WidgetStatePropertyAll(contentTheme.primary.withAlpha(40)), dataRowMaxHeight: 60, showBottomBorder: true, clipBehavior: Clip.antiAliasWithSaveLayer, border: TableBorder.all( borderRadius: BorderRadius.circular(4), style: BorderStyle.solid, width: 0.4, color: Colors.grey, ), columns: [ DataColumn( label: MyText.labelLarge('Name', color: contentTheme.primary)), DataColumn( label: MyText.labelLarge('Role', color: contentTheme.primary)), DataColumn( label: MyText.labelLarge('Check-In', color: contentTheme.primary)), DataColumn( label: MyText.labelLarge('Check-Out', color: contentTheme.primary)), DataColumn( label: MyText.labelLarge('Action', color: contentTheme.primary)), ], rows: attendanceController.attendanceLogs .mapIndexed((index, log) => DataRow(cells: [ DataCell( MyText.bodyMedium(log.name, fontWeight: 600)), DataCell( MyText.bodyMedium(log.role, fontWeight: 600)), DataCell(MyText.bodyMedium( log.checkIn != null ? DateFormat('dd MMM yyyy hh:mm a') .format(log.checkIn!) : '-', fontWeight: 600, )), DataCell(MyText.bodyMedium( log.checkOut != null ? DateFormat('dd MMM yyyy hh:mm a') .format(log.checkOut!) : '-', fontWeight: 600, )), DataCell( ElevatedButton( onPressed: () async { // Call fetchLogsView to load the log data await attendanceController.fetchLogsView(log.id .toString()); // Assuming `log.id` is available // Open the bottom sheet to display the log details showModalBottomSheet( context: context, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical( top: Radius.circular(16)), ), backgroundColor: theme.cardTheme.color, builder: (context) { return Padding( padding: const EdgeInsets.all(16.0), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ MyText.titleMedium( "Attendance Log Details", fontWeight: 700), const SizedBox(height: 16), // Display the log details if (attendanceController .attendenceLogsView.isNotEmpty) ...attendanceController .attendenceLogsView .map((log) => Column( crossAxisAlignment: CrossAxisAlignment .start, children: [ MyText.bodyMedium( "Date: ${log.formattedDate ?? '-'}", fontWeight: 600, ), MyText.bodyMedium( "Time: ${log.formattedTime ?? '-'}", fontWeight: 600, ), MyText.bodyMedium( "Description: ${log.description ?? '-'}", fontWeight: 600, ), const Divider( thickness: 1, height: 24), ], )), Align( alignment: Alignment.centerRight, child: ElevatedButton( onPressed: () => Navigator.pop(context), child: const Text("Close"), ), ) ], ), ); }, ); }, child: const Text('View'), ), ) ])) .toList(), ), ), ), ], ); } Widget regularizationTab(BuildContext context) { final attendanceController = Get.find(); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.all(8.0), ), if (attendanceController.regularizationLogs.isEmpty) Expanded( child: Center( child: MyText.bodySmall("No Regularization Records Found", fontWeight: 600), ), ) else Expanded( child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: DataTable( sortAscending: true, columnSpacing: 15, headingRowColor: WidgetStatePropertyAll(contentTheme.primary.withAlpha(40)), dataRowMaxHeight: 60, showBottomBorder: true, clipBehavior: Clip.antiAliasWithSaveLayer, border: TableBorder.all( borderRadius: BorderRadius.circular(4), style: BorderStyle.solid, width: 0.4, color: Colors.grey, ), columns: [ DataColumn( label: MyText.labelLarge('Name', color: contentTheme.primary)), DataColumn( label: MyText.labelLarge('Role', color: contentTheme.primary)), DataColumn( label: MyText.labelLarge('Check-In', color: contentTheme.primary)), DataColumn( label: MyText.labelLarge('Check-Out', color: contentTheme.primary)), DataColumn( label: MyText.labelLarge('Action', color: contentTheme.primary)), ], rows: attendanceController.regularizationLogs .mapIndexed((index, log) => DataRow(cells: [ DataCell( MyText.bodyMedium(log.name, fontWeight: 600)), DataCell( MyText.bodyMedium(log.role, fontWeight: 600)), DataCell(MyText.bodyMedium( log.checkIn != null ? DateFormat('dd MMM yyyy hh:mm a') .format(log.checkIn!) : '-', fontWeight: 600, )), DataCell(MyText.bodyMedium( log.checkOut != null ? DateFormat('dd MMM yyyy hh:mm a') .format(log.checkOut!) : '-', fontWeight: 600, )), DataCell(IconButton( icon: Icon(Icons.info_outline, color: contentTheme.primary), onPressed: () { // Add action logic }, )), ])) .toList(), ), ), ), ], ); } }