From 501bec819fef7aa26b6f56cda724c62619e426c8 Mon Sep 17 00:00:00 2001 From: Vaibhav Surve Date: Fri, 16 May 2025 16:24:11 +0530 Subject: [PATCH] Refactor AttendanceScreen to improve project selection and refresh logic --- lib/view/dashboard/attendanceScreen.dart | 436 ++++++++++++----------- 1 file changed, 236 insertions(+), 200 deletions(-) diff --git a/lib/view/dashboard/attendanceScreen.dart b/lib/view/dashboard/attendanceScreen.dart index e0ce957..fc8b2d6 100644 --- a/lib/view/dashboard/attendanceScreen.dart +++ b/lib/view/dashboard/attendanceScreen.dart @@ -40,200 +40,181 @@ class _AttendanceScreenState extends State with UIMixin { @override Widget build(BuildContext context) { return Layout( - child: MyRefreshableContent( - onRefresh: () async { - if (attendanceController.selectedProjectId != null) { - await attendanceController.fetchEmployeesByProject( - attendanceController.selectedProjectId!); - await attendanceController - .fetchAttendanceLogs(attendanceController.selectedProjectId!); - await attendanceController - .fetchProjectData(attendanceController.selectedProjectId!); - await attendanceController - .fetchProjectData(attendanceController.selectedProjectId!); - attendanceController.update(); - } else { - await attendanceController.fetchProjects(); - } - }, - child: GetBuilder( - init: attendanceController, - tag: 'attendance_dashboard_controller', - builder: (controller) { - return LoadingComponent( - isLoading: controller.isLoading.value, - loadingText: 'Loading Attendance...', - child: 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), - ], - ), - ], - ), + child: GetBuilder( + init: attendanceController, + tag: 'attendance_dashboard_controller', + builder: (controller) { + return LoadingComponent( + isLoading: controller.isLoading.value, + loadingText: 'Loading Attendance...', + child: 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: MyFlex( - children: [ - // Project Selection Dropdown - MyFlexItem( - sizes: 'lg-12', - child: MyContainer.bordered( - padding: MySpacing.xy(8, 8), - child: PopupMenuButton( - onSelected: (value) async { - attendanceController.selectedProjectId = value; - await attendanceController - .fetchEmployeesByProject(value); - await attendanceController - .fetchAttendanceLogs(value); - await attendanceController - .fetchRegularizationLogs(value); - await attendanceController - .fetchProjectData(value); - attendanceController.update(); - }, - itemBuilder: (BuildContext context) { - if (attendanceController.projects.isEmpty) { - return [ - PopupMenuItem( - value: '', - child: MyText.bodySmall('No Data', - fontWeight: 600), - ) - ]; - } - // Filter projects based on permissions - final accessibleProjects = attendanceController - .projects - .where((project) => permissionController - .isUserAssignedToProject( - project.id.toString())) - .toList(); + ), + MySpacing.height(flexSpacing), + Padding( + padding: MySpacing.x(flexSpacing / 2), + child: MyFlex( + children: [ + // Project Selection Dropdown + MyFlexItem( + sizes: 'lg-12', + child: MyContainer.bordered( + padding: MySpacing.xy(8, 8), + child: PopupMenuButton( + onSelected: (value) async { + attendanceController.selectedProjectId = value; + await attendanceController + .fetchEmployeesByProject(value); + await attendanceController + .fetchAttendanceLogs(value); + await attendanceController + .fetchRegularizationLogs(value); + await attendanceController + .fetchProjectData(value); + attendanceController.update(); + }, + itemBuilder: (BuildContext context) { + if (attendanceController.projects.isEmpty) { + return [ + PopupMenuItem( + value: '', + child: MyText.bodySmall('No Data', + fontWeight: 600), + ) + ]; + } + // Filter projects based on permissions + final accessibleProjects = attendanceController + .projects + .where((project) => permissionController + .isUserAssignedToProject( + project.id.toString())) + .toList(); - if (accessibleProjects.isEmpty) { - return [ - PopupMenuItem( - value: '', - child: MyText.bodySmall( - 'No Projects Assigned', - fontWeight: 600), - ) - ]; - } - - return accessibleProjects.map((project) { - return PopupMenuItem( - value: project.id.toString(), - height: 32, + if (accessibleProjects.isEmpty) { + return [ + PopupMenuItem( + value: '', 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 == - attendanceController - .selectedProjectId) - ?.name ?? - 'Select a Project' - : 'Select a Project', + 'No Projects Assigned', + fontWeight: 600), + ) + ]; + } + + return accessibleProjects.map((project) { + return PopupMenuItem( + value: project.id.toString(), + height: 32, + child: MyText.bodySmall( + project.name, color: theme.colorScheme.onSurface, + fontWeight: 600, ), - Icon(LucideIcons.chevron_down, - size: 20, - color: theme.colorScheme.onSurface), - ], - ), + ); + }).toList(); + }, + color: theme.cardTheme.color, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + MyText.labelSmall( + attendanceController.selectedProjectId != null + ? attendanceController.projects + .firstWhereOrNull((proj) => + proj.id == + attendanceController + .selectedProjectId) + ?.name ?? + 'Select a Project' + : 'Select a Project', + color: theme.colorScheme.onSurface, + ), + Icon(LucideIcons.chevron_down, + size: 20, + color: theme.colorScheme.onSurface), + ], ), ), ), + ), - // Tab Section - MyFlexItem( - sizes: 'lg-12', - child: Obx(() { - bool hasRegularizationPermission = - permissionController.hasPermission( - Permissions.regularizeAttendance); + // Tab Section + MyFlexItem( + sizes: 'lg-12', + child: Obx(() { + bool hasRegularizationPermission = + permissionController.hasPermission( + Permissions.regularizeAttendance); - final tabs = [ - const Tab(text: 'Employee List'), - const Tab(text: 'Logs'), - if (hasRegularizationPermission) - const Tab(text: 'Regularization'), - ]; + final tabs = [ + const Tab(text: 'Employee List'), + const Tab(text: 'Logs'), + if (hasRegularizationPermission) + const Tab(text: 'Regularization'), + ]; - final views = [ - employeeListTab(), - reportsTab(context), - if (hasRegularizationPermission) - regularizationTab(context), - ]; + final views = [ + employeeListTab(), + reportsTab(context), + if (hasRegularizationPermission) + regularizationTab(context), + ]; - return DefaultTabController( - length: tabs.length, - 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: tabs, - ), - MySpacing.height(16), - SizedBox( - height: 550, - child: TabBarView(children: views), - ), - ], - ), + return DefaultTabController( + length: tabs.length, + 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: tabs, + ), + MySpacing.height(16), + SizedBox( + height: 550, + child: TabBarView(children: views), + ), + ], ), - ); - }), - ), - ], - ), + ), + ); + }), + ), + ], ), - ], - ), - ); - }, - ), + ), + ], + ), + ); + }, ), ); } @@ -365,13 +346,25 @@ class _AttendanceScreenState extends State with UIMixin { ), ]); }).toList(); - return Padding( padding: const EdgeInsets.all(0.0), child: SingleChildScrollView( - child: MyPaginatedTable( - columns: columns, - rows: rows, + child: MyRefreshableContent( + onRefresh: () async { + if (attendanceController.selectedProjectId != null) { + await attendanceController.fetchEmployeesByProject( + attendanceController.selectedProjectId!); + await attendanceController + .fetchProjectData(attendanceController.selectedProjectId!); + attendanceController.update(); + } else { + await attendanceController.fetchProjects(); + } + }, + child: MyPaginatedTable( + columns: columns, + rows: rows, + ), ), ), ); @@ -832,11 +825,28 @@ class _AttendanceScreenState extends State with UIMixin { children: [ Padding( padding: const EdgeInsets.all(8.0), - child: TextButton.icon( - icon: const Icon(Icons.date_range), - label: const Text("Select Date Range for Attendance"), - onPressed: () => attendanceController - .selectDateRangeForAttendance(context, attendanceController), + child: GetBuilder( + id: 'attendance_dashboard_controller', + builder: (controller) { + String labelText; + if (controller.startDateAttendance != null && + controller.endDateAttendance != null) { + final start = DateFormat('dd MM yyyy') + .format(controller.startDateAttendance!); + final end = DateFormat('dd MM yyyy') + .format(controller.endDateAttendance!); + labelText = "$start - $end"; + } else { + labelText = "Select Date Range for Attendance"; + } + + return TextButton.icon( + icon: const Icon(Icons.date_range), + label: Text(labelText, overflow: TextOverflow.ellipsis), + onPressed: () => controller.selectDateRangeForAttendance( + Get.context!, controller), + ); + }, ), ), if (attendanceController.attendanceLogs.isEmpty) @@ -851,12 +861,25 @@ class _AttendanceScreenState extends State with UIMixin { ), ) else - SingleChildScrollView( - child: MyPaginatedTable( - columns: columns, - rows: rows, + MyRefreshableContent( + onRefresh: () async { + if (attendanceController.selectedProjectId != null) { + await attendanceController.fetchAttendanceLogs( + attendanceController.selectedProjectId!); + await attendanceController.fetchProjectData( + attendanceController.selectedProjectId!); + attendanceController.update(); + } else { + await attendanceController.fetchProjects(); + } + }, + child: SingleChildScrollView( + child: MyPaginatedTable( + columns: columns, + rows: rows, + ), ), - ), + ) ], ), ); @@ -1120,14 +1143,27 @@ class _AttendanceScreenState extends State with UIMixin { ) else Expanded( - child: SingleChildScrollView( - child: MyPaginatedTable( - columns: columns, - rows: rows, - columnSpacing: 15.0, + child: MyRefreshableContent( + onRefresh: () async { + if (attendanceController.selectedProjectId != null) { + await attendanceController.fetchProjectData( + attendanceController.selectedProjectId!); + await attendanceController.fetchRegularizationLogs( + attendanceController.selectedProjectId!); + attendanceController.update(); + } else { + await attendanceController.fetchProjects(); + } + }, + child: SingleChildScrollView( + child: MyPaginatedTable( + columns: columns, + rows: rows, + columnSpacing: 15.0, + ), ), ), - ), + ) ], ); }