From 9d9afe37b8a8c63e572b051d497beff1b25a722a Mon Sep 17 00:00:00 2001 From: Vaibhav Surve Date: Sat, 2 Aug 2025 16:44:39 +0530 Subject: [PATCH] refactor: Clean up AttendanceActionButton and AttendanceFilterBottomSheet code by removing unused comment bottom sheet function and filter button properties for improved readability and maintainability. --- .../attendance/attendence_action_button.dart | 358 ++++++++---------- .../attendance/attendence_filter_sheet.dart | 3 - 2 files changed, 153 insertions(+), 208 deletions(-) diff --git a/lib/model/attendance/attendence_action_button.dart b/lib/model/attendance/attendence_action_button.dart index 90d263d..ebbbd9a 100644 --- a/lib/model/attendance/attendence_action_button.dart +++ b/lib/model/attendance/attendence_action_button.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:intl/intl.dart'; + import 'package:marco/helpers/widgets/my_snackbar.dart'; import 'package:marco/controller/dashboard/attendance_screen_controller.dart'; import 'package:marco/helpers/utils/attendance_actions.dart'; @@ -21,76 +22,6 @@ class AttendanceActionButton extends StatefulWidget { State createState() => _AttendanceActionButtonState(); } -Future _showCommentBottomSheet( - BuildContext context, String actionText) async { - final TextEditingController commentController = TextEditingController(); - String? errorText; - - return showModalBottomSheet( - context: context, - isScrollControlled: true, - backgroundColor: Colors.transparent, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.vertical(top: Radius.circular(16)), - ), - builder: (context) { - return StatefulBuilder( - builder: (context, setModalState) { - void submit() { - final comment = commentController.text.trim(); - if (comment.isEmpty) { - setModalState(() => errorText = 'Comment cannot be empty.'); - return; - } - Navigator.of(context).pop(comment); - } - - return Padding( - padding: EdgeInsets.only( - bottom: MediaQuery.of(context).viewInsets.bottom, - ), - child: BaseBottomSheet( - title: 'Add Comment for ${capitalizeFirstLetter(actionText)}', - onCancel: () => Navigator.of(context).pop(), - onSubmit: submit, - isSubmitting: false, - submitText: 'Submit', - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - TextField( - controller: commentController, - maxLines: 4, - decoration: InputDecoration( - hintText: 'Type your comment here...', - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - filled: true, - fillColor: Colors.grey.shade100, - errorText: errorText, - ), - onChanged: (_) { - if (errorText != null) { - setModalState(() => errorText = null); - } - }, - ), - ], - ), - ), - ); - }, - ); - }, - ); -} - -String capitalizeFirstLetter(String text) { - if (text.isEmpty) return text; - return text[0].toUpperCase() + text.substring(1); -} - class _AttendanceActionButtonState extends State { late final String uniqueLogKey; @@ -110,51 +41,45 @@ class _AttendanceActionButtonState extends State { }); } - Future showTimePickerForRegularization({ - required BuildContext context, - required DateTime checkInTime, - }) async { + Future _pickRegularizationTime(DateTime checkInTime) async { final pickedTime = await showTimePicker( context: context, initialTime: TimeOfDay.fromDateTime(DateTime.now()), ); - if (pickedTime != null) { - final selectedDateTime = DateTime( - checkInTime.year, - checkInTime.month, - checkInTime.day, - pickedTime.hour, - pickedTime.minute, + if (pickedTime == null) return null; + + final selected = DateTime( + checkInTime.year, + checkInTime.month, + checkInTime.day, + pickedTime.hour, + pickedTime.minute, + ); + + final now = DateTime.now(); + + if (selected.isBefore(checkInTime)) { + showAppSnackbar( + title: "Invalid Time", + message: "Time must be after check-in.", + type: SnackbarType.warning, ); - - final now = DateTime.now(); - - if (selectedDateTime.isBefore(checkInTime)) { - showAppSnackbar( - title: "Invalid Time", - message: "Time must be after check-in.", - type: SnackbarType.warning, - ); - return null; - } else if (selectedDateTime.isAfter(now)) { - showAppSnackbar( - title: "Invalid Time", - message: "Future time is not allowed.", - type: SnackbarType.warning, - ); - return null; - } - - return selectedDateTime; + return null; + } else if (selected.isAfter(now)) { + showAppSnackbar( + title: "Invalid Time", + message: "Future time is not allowed.", + type: SnackbarType.warning, + ); + return null; } - return null; + return selected; } - void _handleButtonPressed(BuildContext context) async { - widget.attendanceController.uploadingStates[uniqueLogKey]?.value = true; - + Future _handleButtonPressed() async { + final controller = widget.attendanceController; final projectController = Get.find(); final selectedProjectId = projectController.selectedProject?.id; @@ -164,46 +89,43 @@ class _AttendanceActionButtonState extends State { message: "Please select a project first", type: SnackbarType.error, ); - widget.attendanceController.uploadingStates[uniqueLogKey]?.value = false; return; } - int updatedAction; + controller.uploadingStates[uniqueLogKey]?.value = true; + + int action; String actionText; bool imageCapture = true; switch (widget.employee.activity) { case 0: - updatedAction = 0; + case 4: + action = 0; actionText = ButtonActions.checkIn; break; case 1: - if (widget.employee.checkOut == null && - AttendanceButtonHelper.isOlderThanDays( - widget.employee.checkIn, 2)) { - updatedAction = 2; + final isOld = AttendanceButtonHelper.isOlderThanDays(widget.employee.checkIn, 2); + final isOldCheckout = AttendanceButtonHelper.isOlderThanDays(widget.employee.checkOut, 2); + + if (widget.employee.checkOut == null && isOld) { + action = 2; actionText = ButtonActions.requestRegularize; imageCapture = false; - } else if (widget.employee.checkOut != null && - AttendanceButtonHelper.isOlderThanDays( - widget.employee.checkOut, 2)) { - updatedAction = 2; + } else if (widget.employee.checkOut != null && isOldCheckout) { + action = 2; actionText = ButtonActions.requestRegularize; } else { - updatedAction = 1; + action = 1; actionText = ButtonActions.checkOut; } break; case 2: - updatedAction = 2; + action = 2; actionText = ButtonActions.requestRegularize; break; - case 4: - updatedAction = 0; - actionText = ButtonActions.checkIn; - break; default: - updatedAction = 0; + action = 0; actionText = "Unknown Action"; break; } @@ -219,67 +141,41 @@ class _AttendanceActionButtonState extends State { if (isYesterdayCheckIn && widget.employee.checkOut == null && actionText == ButtonActions.checkOut) { - selectedTime = await showTimePickerForRegularization( - context: context, - checkInTime: widget.employee.checkIn!, - ); - + selectedTime = await _pickRegularizationTime(widget.employee.checkIn!); if (selectedTime == null) { - widget.attendanceController.uploadingStates[uniqueLogKey]?.value = - false; + controller.uploadingStates[uniqueLogKey]?.value = false; return; } } - final userComment = await _showCommentBottomSheet(context, actionText); - if (userComment == null || userComment.isEmpty) { - widget.attendanceController.uploadingStates[uniqueLogKey]?.value = false; + final comment = await _showCommentBottomSheet(context, actionText); + if (comment == null || comment.isEmpty) { + controller.uploadingStates[uniqueLogKey]?.value = false; return; } bool success = false; + String? markTime; if (actionText == ButtonActions.requestRegularize) { - final regularizeTime = selectedTime ?? - await showTimePickerForRegularization( - context: context, - checkInTime: widget.employee.checkIn!, - ); - - if (regularizeTime != null) { - final formattedTime = DateFormat("hh:mm a").format(regularizeTime); - success = await widget.attendanceController.captureAndUploadAttendance( - widget.employee.id, - widget.employee.employeeId, - selectedProjectId, - comment: userComment, - action: updatedAction, - imageCapture: imageCapture, - markTime: formattedTime, - ); + selectedTime ??= await _pickRegularizationTime(widget.employee.checkIn!); + if (selectedTime != null) { + markTime = DateFormat("hh:mm a").format(selectedTime); } } else if (selectedTime != null) { - final formattedTime = DateFormat("hh:mm a").format(selectedTime); - success = await widget.attendanceController.captureAndUploadAttendance( - widget.employee.id, - widget.employee.employeeId, - selectedProjectId, - comment: userComment, - action: updatedAction, - imageCapture: imageCapture, - markTime: formattedTime, - ); - } else { - success = await widget.attendanceController.captureAndUploadAttendance( - widget.employee.id, - widget.employee.employeeId, - selectedProjectId, - comment: userComment, - action: updatedAction, - imageCapture: imageCapture, - ); + markTime = DateFormat("hh:mm a").format(selectedTime); } + success = await controller.captureAndUploadAttendance( + widget.employee.id, + widget.employee.employeeId, + selectedProjectId, + comment: comment, + action: action, + imageCapture: imageCapture, + markTime: markTime, + ); + showAppSnackbar( title: success ? '${capitalizeFirstLetter(actionText)} Success' : 'Error', message: success @@ -288,57 +184,47 @@ class _AttendanceActionButtonState extends State { type: success ? SnackbarType.success : SnackbarType.error, ); - widget.attendanceController.uploadingStates[uniqueLogKey]?.value = false; + controller.uploadingStates[uniqueLogKey]?.value = false; if (success) { - widget.attendanceController.fetchEmployeesByProject(selectedProjectId); - widget.attendanceController.fetchAttendanceLogs(selectedProjectId); - await widget.attendanceController.fetchRegularizationLogs(selectedProjectId); - await widget.attendanceController.fetchProjectData(selectedProjectId); - widget.attendanceController.update(); + controller.fetchEmployeesByProject(selectedProjectId); + controller.fetchAttendanceLogs(selectedProjectId); + await controller.fetchRegularizationLogs(selectedProjectId); + await controller.fetchProjectData(selectedProjectId); + controller.update(); } } @override Widget build(BuildContext context) { return Obx(() { - final isUploading = - widget.attendanceController.uploadingStates[uniqueLogKey]?.value ?? - false; + final controller = widget.attendanceController; - final isYesterday = AttendanceButtonHelper.isLogFromYesterday( - widget.employee.checkIn, - widget.employee.checkOut, - ); + final isUploading = controller.uploadingStates[uniqueLogKey]?.value ?? false; + final emp = widget.employee; - final isTodayApproved = AttendanceButtonHelper.isTodayApproved( - widget.employee.activity, - widget.employee.checkIn, - ); - - final isApprovedButNotToday = AttendanceButtonHelper.isApprovedButNotToday( - widget.employee.activity, - isTodayApproved, - ); + final isYesterday = AttendanceButtonHelper.isLogFromYesterday(emp.checkIn, emp.checkOut); + final isTodayApproved = AttendanceButtonHelper.isTodayApproved(emp.activity, emp.checkIn); + final isApprovedButNotToday = AttendanceButtonHelper.isApprovedButNotToday(emp.activity, isTodayApproved); final isButtonDisabled = AttendanceButtonHelper.isButtonDisabled( isUploading: isUploading, isYesterday: isYesterday, - activity: widget.employee.activity, + activity: emp.activity, isApprovedButNotToday: isApprovedButNotToday, ); final buttonText = AttendanceButtonHelper.getButtonText( - activity: widget.employee.activity, - checkIn: widget.employee.checkIn, - checkOut: widget.employee.checkOut, + activity: emp.activity, + checkIn: emp.checkIn, + checkOut: emp.checkOut, isTodayApproved: isTodayApproved, ); final buttonColor = AttendanceButtonHelper.getButtonColor( isYesterday: isYesterday, isTodayApproved: isTodayApproved, - activity: widget.employee.activity, + activity: emp.activity, ); return AttendanceActionButtonUI( @@ -346,7 +232,7 @@ class _AttendanceActionButtonState extends State { isButtonDisabled: isButtonDisabled, buttonText: buttonText, buttonColor: buttonColor, - onPressed: isButtonDisabled ? null : () => _handleButtonPressed(context), + onPressed: isButtonDisabled ? null : _handleButtonPressed, ); }); } @@ -391,17 +277,14 @@ class AttendanceActionButtonUI extends StatelessWidget { : Row( mainAxisSize: MainAxisSize.min, children: [ - if (buttonText.toLowerCase() == 'approved') ...[ + if (buttonText.toLowerCase() == 'approved') const Icon(Icons.check, size: 16, color: Colors.green), - const SizedBox(width: 4), - ] else if (buttonText.toLowerCase() == 'rejected') ...[ + if (buttonText.toLowerCase() == 'rejected') const Icon(Icons.close, size: 16, color: Colors.red), + if (buttonText.toLowerCase() == 'requested') + const Icon(Icons.hourglass_top, size: 16, color: Colors.orange), + if (['approved', 'rejected', 'requested'].contains(buttonText.toLowerCase())) const SizedBox(width: 4), - ] else if (buttonText.toLowerCase() == 'requested') ...[ - const Icon(Icons.hourglass_top, - size: 16, color: Colors.orange), - const SizedBox(width: 4), - ], Flexible( child: Text( buttonText, @@ -415,3 +298,68 @@ class AttendanceActionButtonUI extends StatelessWidget { ); } } + +Future _showCommentBottomSheet(BuildContext context, String actionText) async { + final commentController = TextEditingController(); + String? errorText; + + return showModalBottomSheet( + context: context, + isScrollControlled: true, + backgroundColor: Colors.transparent, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(16)), + ), + builder: (context) { + return StatefulBuilder( + builder: (context, setModalState) { + void submit() { + final comment = commentController.text.trim(); + if (comment.isEmpty) { + setModalState(() => errorText = 'Comment cannot be empty.'); + return; + } + Navigator.of(context).pop(comment); + } + + return Padding( + padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), + child: BaseBottomSheet( + title: 'Add Comment for ${capitalizeFirstLetter(actionText)}', + onCancel: () => Navigator.of(context).pop(), + onSubmit: submit, + isSubmitting: false, + submitText: 'Submit', + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TextField( + controller: commentController, + maxLines: 4, + decoration: InputDecoration( + hintText: 'Type your comment here...', + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + filled: true, + fillColor: Colors.grey.shade100, + errorText: errorText, + ), + onChanged: (_) { + if (errorText != null) { + setModalState(() => errorText = null); + } + }, + ), + ], + ), + ), + ); + }, + ); + }, + ); +} + +String capitalizeFirstLetter(String text) => + text.isEmpty ? text : text[0].toUpperCase() + text.substring(1); diff --git a/lib/model/attendance/attendence_filter_sheet.dart b/lib/model/attendance/attendence_filter_sheet.dart index 32fbc43..53d371a 100644 --- a/lib/model/attendance/attendence_filter_sheet.dart +++ b/lib/model/attendance/attendence_filter_sheet.dart @@ -137,9 +137,6 @@ class _AttendanceFilterBottomSheetState onSubmit: () => Navigator.pop(context, { 'selectedTab': tempSelectedTab, }), - submitText: "Apply Filter", - submitIcon: Icons.filter_alt_outlined, - submitColor: const Color.fromARGB(255, 95, 132, 255), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: buildMainFilters(),