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); }); }, 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: 2, 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'), ], ), MySpacing.height(16), SizedBox( height: 500, child: TabBarView( children: [ employeeListTab(), reportsTab(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 ? 'Image uploaded 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"), onPressed: () => attendanceController.selectDateRange(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(IconButton( icon: Icon(Icons.info_outline, color: contentTheme.primary), onPressed: () { // Add action logic }, )), ])) .toList(), ), ), ), ], ); } }