From 938bf58ff6b1cd1df59b7ed44f8c0bf2dd3b6618 Mon Sep 17 00:00:00 2001 From: Vaibhav Surve Date: Fri, 30 May 2025 14:41:04 +0530 Subject: [PATCH] feat: Enhance ReportTaskController with image picking and form field management - Added image picking functionality using ImagePicker for selecting images from camera or gallery. - Refactored form field controllers in ReportTaskController for better management and disposal. - Updated reportTask and commentTask methods to use the new controller references. - Implemented image removal functionality in ReportTaskController. - Modified ReportTaskBottomSheet to clear fields upon initialization and added a callback for successful reports. - Updated attendance and regularization logs UI for better loading states and error handling. - Improved logout functionality in LocalStorage and integrated it into layout and left bar components. - Adjusted initial route logic in main.dart to redirect users based on authentication status. --- .../attendance_screen_controller.dart | 94 +- .../task_planing/report_task_controller.dart | 160 ++-- lib/helpers/services/permission_service.dart | 19 +- .../services/storage/local_storage.dart | 16 +- lib/main.dart | 58 +- .../attendance/attendence_filter_sheet.dart | 26 +- .../comment_task_bottom_sheet.dart | 1 + .../report_task_bottom_sheet.dart | 12 +- lib/routes.dart | 6 +- .../Attendence/attendance_screen.dart | 857 +++++++++--------- lib/view/layouts/layout.dart | 4 +- lib/view/layouts/left_bar.dart | 11 +- lib/view/taskPlaning/daily_progress.dart | 11 +- 13 files changed, 673 insertions(+), 602 deletions(-) diff --git a/lib/controller/dashboard/attendance_screen_controller.dart b/lib/controller/dashboard/attendance_screen_controller.dart index 4a950f2..234c2c3 100644 --- a/lib/controller/dashboard/attendance_screen_controller.dart +++ b/lib/controller/dashboard/attendance_screen_controller.dart @@ -1,41 +1,49 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:image_picker/image_picker.dart'; import 'package:geolocator/geolocator.dart'; import 'package:intl/intl.dart'; import 'package:logger/logger.dart'; -import 'dart:io'; + import 'package:marco/helpers/services/api_service.dart'; +import 'package:marco/helpers/widgets/my_image_compressor.dart'; import 'package:marco/model/attendance_model.dart'; import 'package:marco/model/project_model.dart'; import 'package:marco/model/employee_model.dart'; import 'package:marco/model/attendance_log_model.dart'; import 'package:marco/model/regularization_log_model.dart'; import 'package:marco/model/attendance_log_view_model.dart'; -import 'package:marco/helpers/widgets/my_image_compressor.dart'; final Logger log = Logger(); class AttendanceController extends GetxController { + // Data lists List attendances = []; List projects = []; - String? selectedProjectId; List employees = []; - String selectedTab = 'Employee List'; - DateTime? startDateAttendance; - DateTime? endDateAttendance; - List attendanceLogs = []; List regularizationLogs = []; List attendenceLogsView = []; - RxBool isLoading = true.obs; // initially true + // Selected values + String? selectedProjectId; + String selectedTab = 'Employee List'; + + // Date range for attendance filtering + DateTime? startDateAttendance; + DateTime? endDateAttendance; + + // Loading states + RxBool isLoading = true.obs; RxBool isLoadingProjects = true.obs; RxBool isLoadingEmployees = true.obs; RxBool isLoadingAttendanceLogs = true.obs; RxBool isLoadingRegularizationLogs = true.obs; RxBool isLoadingLogView = true.obs; + // Uploading state per employee (keyed by employeeId) RxMap uploadingStates = {}.obs; @override @@ -46,7 +54,7 @@ class AttendanceController extends GetxController { void _initializeDefaults() { _setDefaultDateRange(); - fetchProjects(); // fetchProjects will set isLoading to false after loading + fetchProjects(); } void _setDefaultDateRange() { @@ -56,8 +64,10 @@ class AttendanceController extends GetxController { log.i("Default date range set: $startDateAttendance to $endDateAttendance"); } + /// Checks and requests location permission, returns true if granted. Future _handleLocationPermission() async { LocationPermission permission = await Geolocator.checkPermission(); + if (permission == LocationPermission.denied) { permission = await Geolocator.requestPermission(); if (permission == LocationPermission.denied) { @@ -65,13 +75,16 @@ class AttendanceController extends GetxController { return false; } } + if (permission == LocationPermission.deniedForever) { log.e('Location permissions are permanently denied'); return false; } + return true; } + /// Fetches projects and initializes selected project. Future fetchProjects() async { isLoadingProjects.value = true; isLoading.value = true; @@ -81,11 +94,11 @@ class AttendanceController extends GetxController { if (response != null && response.isNotEmpty) { projects = response.map((json) => ProjectModel.fromJson(json)).toList(); selectedProjectId = projects.first.id.toString(); - log.i("Projects fetched: ${projects.length} projects loaded."); + log.i("Projects fetched: ${projects.length}"); await fetchProjectData(selectedProjectId); } else { - log.w("No project data found or API call failed."); + log.w("No projects found or API call failed."); } isLoadingProjects.value = false; @@ -94,6 +107,7 @@ class AttendanceController extends GetxController { update(['attendance_dashboard_controller']); } + /// Fetches employees, attendance logs and regularization logs for a project. Future fetchProjectData(String? projectId) async { if (projectId == null) return; @@ -107,9 +121,11 @@ class AttendanceController extends GetxController { ]); isLoading.value = false; + log.i("Project data fetched for project ID: $projectId"); } + /// Fetches employees for the given project. Future fetchEmployeesByProject(String? projectId) async { if (projectId == null) return; @@ -120,18 +136,22 @@ class AttendanceController extends GetxController { if (response != null) { employees = response.map((json) => EmployeeModel.fromJson(json)).toList(); + // Initialize uploading states for employees for (var emp in employees) { uploadingStates[emp.id] = false.obs; } - log.i( - "Employees fetched: ${employees.length} employees for project $projectId"); + + log.i("Employees fetched: ${employees.length} for project $projectId"); update(); } else { log.e("Failed to fetch employees for project $projectId"); } + isLoadingEmployees.value = false; } + /// Captures image, gets location, and uploads attendance data. + /// Returns true on success. Future captureAndUploadAttendance( String id, String employeeId, @@ -155,8 +175,8 @@ class AttendanceController extends GetxController { uploadingStates[employeeId]?.value = false; return false; } - final compressedBytes = - await compressImageToUnder100KB(File(image.path)); + + final compressedBytes = await compressImageToUnder100KB(File(image.path)); if (compressedBytes == null) { log.e("Image compression failed."); uploadingStates[employeeId]?.value = false; @@ -205,6 +225,7 @@ class AttendanceController extends GetxController { } } + /// Opens a date range picker for attendance filtering and fetches logs on selection. Future selectDateRangeForAttendance( BuildContext context, AttendanceController controller, @@ -217,18 +238,10 @@ class AttendanceController extends GetxController { firstDate: DateTime(2022), lastDate: todayDateOnly.subtract(const Duration(days: 1)), initialDateRange: DateTimeRange( - start: startDateAttendance ?? - DateTime.now().subtract(const Duration(days: 7)), - end: endDateAttendance ?? - todayDateOnly.subtract(const Duration(days: 1)), + start: startDateAttendance ?? today.subtract(const Duration(days: 7)), + end: endDateAttendance ?? todayDateOnly.subtract(const Duration(days: 1)), ), - selectableDayPredicate: (DateTime day, DateTime? start, DateTime? end) { - final dayDateOnly = DateTime(day.year, day.month, day.day); - if (dayDateOnly == todayDateOnly) { - return false; - } - return true; - }, + builder: (BuildContext context, Widget? child) { return Center( child: SizedBox( @@ -242,13 +255,9 @@ class AttendanceController extends GetxController { onSurface: Colors.teal.shade800, ), textButtonTheme: TextButtonThemeData( - style: TextButton.styleFrom( - foregroundColor: Colors.teal, - ), - ), - dialogTheme: DialogTheme( - backgroundColor: Colors.white, + style: TextButton.styleFrom(foregroundColor: Colors.teal), ), + dialogTheme: const DialogTheme(backgroundColor: Colors.white), ), child: child!, ), @@ -256,6 +265,7 @@ class AttendanceController extends GetxController { ); }, ); + if (picked != null) { startDateAttendance = picked.start; endDateAttendance = picked.end; @@ -270,6 +280,7 @@ class AttendanceController extends GetxController { } } + /// Fetches attendance logs filtered by project and date range. Future fetchAttendanceLogs( String? projectId, { DateTime? dateFrom, @@ -294,10 +305,12 @@ class AttendanceController extends GetxController { } else { log.e("Failed to fetch attendance logs for project $projectId"); } + isLoadingAttendanceLogs.value = false; isLoading.value = false; } + /// Groups attendance logs by check-in date formatted as 'dd MMM yyyy'. Map> groupLogsByCheckInDate() { final groupedLogs = >{}; @@ -309,6 +322,7 @@ class AttendanceController extends GetxController { groupedLogs.putIfAbsent(checkInDate, () => []); groupedLogs[checkInDate]!.add(logItem); } + final sortedEntries = groupedLogs.entries.toList() ..sort((a, b) { if (a.key == 'Unknown') return 1; @@ -318,13 +332,13 @@ class AttendanceController extends GetxController { return dateB.compareTo(dateA); }); - final sortedMap = - Map>.fromEntries(sortedEntries); + final sortedMap = Map>.fromEntries(sortedEntries); log.i("Logs grouped and sorted by check-in date."); return sortedMap; } + /// Fetches regularization logs for a project. Future fetchRegularizationLogs( String? projectId, { DateTime? dateFrom, @@ -338,18 +352,19 @@ class AttendanceController extends GetxController { final response = await ApiService.getRegularizationLogs(projectId); if (response != null) { - regularizationLogs = response - .map((json) => RegularizationLogModel.fromJson(json)) - .toList(); + regularizationLogs = + response.map((json) => RegularizationLogModel.fromJson(json)).toList(); log.i("Regularization logs fetched: ${regularizationLogs.length}"); update(); } else { log.e("Failed to fetch regularization logs for project $projectId"); } + isLoadingRegularizationLogs.value = false; isLoading.value = false; } + /// Fetches detailed attendance log view for a specific ID. Future fetchLogsView(String? id) async { if (id == null) return; @@ -359,9 +374,8 @@ class AttendanceController extends GetxController { final response = await ApiService.getAttendanceLogView(id); if (response != null) { - attendenceLogsView = response - .map((json) => AttendanceLogViewModel.fromJson(json)) - .toList(); + attendenceLogsView = + response.map((json) => AttendanceLogViewModel.fromJson(json)).toList(); attendenceLogsView.sort((a, b) { if (a.activityTime == null || b.activityTime == null) return 0; diff --git a/lib/controller/task_planing/report_task_controller.dart b/lib/controller/task_planing/report_task_controller.dart index 05b0d03..6c47545 100644 --- a/lib/controller/task_planing/report_task_controller.dart +++ b/lib/controller/task_planing/report_task_controller.dart @@ -7,11 +7,17 @@ import 'package:get/get.dart'; import 'package:logger/logger.dart'; import 'package:marco/helpers/widgets/my_snackbar.dart'; import 'package:marco/controller/task_planing/daily_task_planing_controller.dart'; +import 'package:image_picker/image_picker.dart'; +import 'dart:io'; final Logger logger = Logger(); enum ApiStatus { idle, loading, success, failure } -final DailyTaskPlaningController taskController = Get.put(DailyTaskPlaningController()); + +final DailyTaskPlaningController taskController = + Get.put(DailyTaskPlaningController()); +final ImagePicker _picker = ImagePicker(); + class ReportTaskController extends MyController { List files = []; MyFormValidator basicValidator = MyFormValidator(); @@ -19,74 +25,71 @@ class ReportTaskController extends MyController { Rx reportStatus = ApiStatus.idle.obs; Rx commentStatus = ApiStatus.idle.obs; + RxList selectedImages = [].obs; + + // Controllers for each form field + final assignedDateController = TextEditingController(); + final workAreaController = TextEditingController(); + final activityController = TextEditingController(); + final teamSizeController = TextEditingController(); + final taskIdController = TextEditingController(); + final assignedController = TextEditingController(); + final completedWorkController = TextEditingController(); + final commentController = TextEditingController(); + final assignedByController = TextEditingController(); + final teamMembersController = TextEditingController(); + final plannedWorkController = TextEditingController(); + @override void onInit() { super.onInit(); logger.i("Initializing ReportTaskController..."); - // Add form fields to the validator - basicValidator.addField( - 'assigned_date', - label: "Assigned Date", - controller: TextEditingController(), - ); - basicValidator.addField( - 'work_area', - label: "Work Area", - controller: TextEditingController(), - ); - basicValidator.addField( - 'activity', - label: "Activity", - controller: TextEditingController(), - ); - basicValidator.addField( - 'team_size', - label: "Team Size", - controller: TextEditingController(), - ); - basicValidator.addField( - 'task_id', - label: "Task Id", - controller: TextEditingController(), - ); - basicValidator.addField( - 'assigned', - label: "Assigned", - controller: TextEditingController(), - ); - basicValidator.addField( - 'completed_work', - label: "Completed Work", - required: true, - controller: TextEditingController(), - ); - basicValidator.addField( - 'comment', - label: "Comment", - required: true, - controller: TextEditingController(), - ); - basicValidator.addField( - 'assigned_by', - label: "Assigned By", - controller: TextEditingController(), - ); - basicValidator.addField( - 'team_members', - label: "Team Members", - controller: TextEditingController(), - ); - basicValidator.addField( - 'planned_work', - label: "Planned Work", - controller: TextEditingController(), - ); + basicValidator.addField('assigned_date', + label: "Assigned Date", controller: assignedDateController); + basicValidator.addField('work_area', + label: "Work Area", controller: workAreaController); + basicValidator.addField('activity', + label: "Activity", controller: activityController); + basicValidator.addField('team_size', + label: "Team Size", controller: teamSizeController); + basicValidator.addField('task_id', + label: "Task Id", controller: taskIdController); + basicValidator.addField('assigned', + label: "Assigned", controller: assignedController); + basicValidator.addField('completed_work', + label: "Completed Work", + required: true, + controller: completedWorkController); + basicValidator.addField('comment', + label: "Comment", required: true, controller: commentController); + basicValidator.addField('assigned_by', + label: "Assigned By", controller: assignedByController); + basicValidator.addField('team_members', + label: "Team Members", controller: teamMembersController); + basicValidator.addField('planned_work', + label: "Planned Work", controller: plannedWorkController); logger.i( "Fields initialized for assigned_date, work_area, activity, team_size, assigned, completed_work, and comment."); } + @override + void onClose() { + assignedDateController.dispose(); + workAreaController.dispose(); + activityController.dispose(); + teamSizeController.dispose(); + taskIdController.dispose(); + assignedController.dispose(); + completedWorkController.dispose(); + commentController.dispose(); + assignedByController.dispose(); + teamMembersController.dispose(); + plannedWorkController.dispose(); + super.onClose(); + } + Future reportTask({ required String projectId, required String comment, @@ -96,10 +99,9 @@ class ReportTaskController extends MyController { }) async { logger.i("Starting task report..."); - final completedWork = - basicValidator.getController('completed_work')?.text.trim(); + final completedWork = completedWorkController.text.trim(); - if (completedWork == null || completedWork.isEmpty) { + if (completedWork.isEmpty) { showAppSnackbar( title: "Error", message: "Completed work is required.", @@ -107,6 +109,7 @@ class ReportTaskController extends MyController { ); return; } + final completedWorkInt = int.tryParse(completedWork); if (completedWorkInt == null || completedWorkInt <= 0) { showAppSnackbar( @@ -116,9 +119,9 @@ class ReportTaskController extends MyController { ); return; } - final commentField = basicValidator.getController('comment')?.text.trim(); - if (commentField == null || commentField.isEmpty) { + final commentField = commentController.text.trim(); + if (commentField.isEmpty) { showAppSnackbar( title: "Error", message: "Comment is required.", @@ -143,6 +146,7 @@ class ReportTaskController extends MyController { message: "Task reported successfully!", type: SnackbarType.success, ); + await taskController.fetchTaskData(projectId); } else { showAppSnackbar( title: "Error", @@ -168,9 +172,8 @@ class ReportTaskController extends MyController { }) async { logger.i("Starting task comment..."); - final commentField = basicValidator.getController('comment')?.text.trim(); - - if (commentField == null || commentField.isEmpty) { + final commentField = commentController.text.trim(); + if (commentField.isEmpty) { showAppSnackbar( title: "Error", message: "Comment is required.", @@ -213,4 +216,27 @@ class ReportTaskController extends MyController { isLoading.value = false; } } + + Future pickImages({required bool fromCamera}) async { + if (fromCamera) { + final pickedFile = await _picker.pickImage( + source: ImageSource.camera, + imageQuality: 75, + ); + if (pickedFile != null) { + selectedImages.add(File(pickedFile.path)); + } + } else { + final pickedFiles = await _picker.pickMultiImage(imageQuality: 75); + if (pickedFiles != null && pickedFiles.isNotEmpty) { + selectedImages.addAll(pickedFiles.map((xfile) => File(xfile.path))); + } + } + } + + void removeImageAt(int index) { + if (index >= 0 && index < selectedImages.length) { + selectedImages.removeAt(index); + } + } } diff --git a/lib/helpers/services/permission_service.dart b/lib/helpers/services/permission_service.dart index a83798f..c0cae90 100644 --- a/lib/helpers/services/permission_service.dart +++ b/lib/helpers/services/permission_service.dart @@ -1,19 +1,20 @@ import 'dart:convert'; import 'package:http/http.dart' as http; import 'package:get/get.dart'; -import 'package:logger/logger.dart'; +import 'package:logger/logger.dart'; import 'package:marco/model/user_permission.dart'; import 'package:marco/model/employee_info.dart'; import 'package:marco/model/projects_model.dart'; import 'package:marco/helpers/services/storage/local_storage.dart'; import 'package:marco/helpers/services/auth_service.dart'; -final Logger logger = Logger(); +final Logger logger = Logger(); class PermissionService { static final Map> _userDataCache = {}; - static Future> fetchAllUserData(String token, {bool hasRetried = false}) async { + static Future> fetchAllUserData(String token, + {bool hasRetried = false}) async { // Return from cache if available if (_userDataCache.containsKey(token)) { return _userDataCache[token]!; @@ -51,10 +52,11 @@ class PermissionService { throw Exception('Unauthorized. Token refresh failed.'); } - final errorMessage = json.decode(response.body)['message'] ?? 'Unknown error'; + final errorMessage = + json.decode(response.body)['message'] ?? 'Unknown error'; throw Exception('Failed to load data: $errorMessage'); } catch (e) { - logger.e('Error fetching user data: $e'); // <-- Use logger here + logger.e('Error fetching user data: $e'); rethrow; } } @@ -66,8 +68,11 @@ class PermissionService { Get.offAllNamed('/auth/login'); } - static List _parsePermissions(List featurePermissions) => - featurePermissions.map((id) => UserPermission.fromJson({'id': id})).toList(); + static List _parsePermissions( + List featurePermissions) => + featurePermissions + .map((id) => UserPermission.fromJson({'id': id})) + .toList(); static EmployeeInfo _parseEmployeeInfo(Map employeeData) => EmployeeInfo.fromJson(employeeData); diff --git a/lib/helpers/services/storage/local_storage.dart b/lib/helpers/services/storage/local_storage.dart index f4b6b63..9504952 100644 --- a/lib/helpers/services/storage/local_storage.dart +++ b/lib/helpers/services/storage/local_storage.dart @@ -5,6 +5,8 @@ import 'package:shared_preferences/shared_preferences.dart'; import 'package:marco/model/user_permission.dart'; import 'package:marco/model/employee_info.dart'; import 'dart:convert'; +import 'package:get/route_manager.dart'; + class LocalStorage { static const String _loggedInUserKey = "user"; static const String _themeCustomizerKey = "theme_customizer"; @@ -43,7 +45,7 @@ class LocalStorage { .toList(); } - return []; // Return empty list if no permissions are found + return []; } static Future removeUserPermissions() async { @@ -62,7 +64,7 @@ class LocalStorage { final Map json = jsonDecode(storedJson); return EmployeeInfo.fromJson(json); } - return null; // Return null if no employee info is found + return null; } static Future removeEmployeeInfo() async { @@ -130,4 +132,14 @@ class LocalStorage { static Future setRefreshToken(String refreshToken) { return setToken(_refreshTokenKey, refreshToken); } + static Future logout() async { + await removeLoggedInUser(); + await removeToken(_jwtTokenKey); + await removeToken(_refreshTokenKey); + await removeUserPermissions(); + await removeEmployeeInfo(); + Get.offAllNamed('/auth/login'); + await preferences.remove(_languageKey); + await preferences.remove(_themeCustomizerKey); + } } diff --git a/lib/main.dart b/lib/main.dart index 9a40f15..9a54e61 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -11,6 +11,7 @@ import 'package:marco/helpers/theme/theme_customizer.dart'; import 'package:marco/routes.dart'; import 'package:provider/provider.dart'; import 'package:url_strategy/url_strategy.dart'; +import 'package:marco/helpers/services/auth_service.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -33,32 +34,47 @@ Future main() async { class MyApp extends StatelessWidget { const MyApp({super.key}); + Future _getInitialRoute() async { + return AuthService.isLoggedIn ? "/dashboard" : "/auth/login"; + } - @override + @override Widget build(BuildContext context) { return Consumer( builder: (_, notifier, ___) { - return GetMaterialApp( - debugShowCheckedModeBanner: false, - theme: AppTheme.lightTheme, - darkTheme: AppTheme.darkTheme, - themeMode: ThemeCustomizer.instance.theme, - navigatorKey: NavigationService.navigatorKey, - initialRoute: "/dashboard", - getPages: getPageRoute(), - builder: (context, child) { - NavigationService.registerContext(context); - return Directionality( - textDirection: AppTheme.textDirection, - child: child ?? Container()); + return FutureBuilder( + future: _getInitialRoute(), + builder: (context, snapshot) { + if (!snapshot.hasData) { + return MaterialApp( + home: Center(child: CircularProgressIndicator()), + ); + } + + return GetMaterialApp( + debugShowCheckedModeBanner: false, + theme: AppTheme.lightTheme, + darkTheme: AppTheme.darkTheme, + themeMode: ThemeCustomizer.instance.theme, + navigatorKey: NavigationService.navigatorKey, + initialRoute: snapshot.data!, + getPages: getPageRoute(), + builder: (context, child) { + NavigationService.registerContext(context); + return Directionality( + textDirection: AppTheme.textDirection, + child: child ?? Container(), + ); + }, + localizationsDelegates: [ + AppLocalizationsDelegate(context), + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: Language.getLocales(), + ); }, - localizationsDelegates: [ - AppLocalizationsDelegate(context), - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - ], - supportedLocales: Language.getLocales(), ); }, ); diff --git a/lib/model/attendance/attendence_filter_sheet.dart b/lib/model/attendance/attendence_filter_sheet.dart index d00e273..d145918 100644 --- a/lib/model/attendance/attendence_filter_sheet.dart +++ b/lib/model/attendance/attendence_filter_sheet.dart @@ -3,6 +3,7 @@ import 'package:marco/controller/permission_controller.dart'; import 'package:marco/controller/dashboard/attendance_screen_controller.dart'; import 'package:intl/intl.dart'; import 'package:marco/helpers/widgets/my_text.dart'; +import 'package:marco/helpers/utils/permission_constants.dart'; class AttendanceFilterBottomSheet extends StatelessWidget { final AttendanceController controller; @@ -38,6 +39,20 @@ class AttendanceFilterBottomSheet extends StatelessWidget { permissionController.isUserAssignedToProject(project.id.toString())) .toList(); + bool hasRegularizationPermission = + permissionController.hasPermission(Permissions.regularizeAttendance); + final viewOptions = [ + {'label': 'Today\'s Attendance', 'value': 'todaysAttendance'}, + {'label': 'Attendance Logs', 'value': 'attendanceLogs'}, + {'label': 'Regularization Requests', 'value': 'regularizationRequests'}, + ]; + final filteredViewOptions = viewOptions.where((item) { + if (item['value'] == 'regularizationRequests') { + return hasRegularizationPermission; + } + return true; + }).toList(); + return StatefulBuilder(builder: (context, setState) { List filterWidgets; @@ -104,14 +119,7 @@ class AttendanceFilterBottomSheet extends StatelessWidget { ), ), ), - ...[ - {'label': 'Today\'s Attendance', 'value': 'todaysAttendance'}, - {'label': 'Attendance Logs', 'value': 'attendanceLogs'}, - { - 'label': 'Regularization Requests', - 'value': 'regularizationRequests' - }, - ].map((item) { + ...filteredViewOptions.map((item) { return RadioListTile( dense: true, contentPadding: const EdgeInsets.symmetric(horizontal: 12), @@ -209,7 +217,7 @@ class AttendanceFilterBottomSheet extends StatelessWidget { width: double.infinity, child: ElevatedButton( style: ElevatedButton.styleFrom( - backgroundColor: Color.fromARGB(255, 95, 132, 255), + backgroundColor: const Color.fromARGB(255, 95, 132, 255), padding: const EdgeInsets.symmetric(vertical: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), diff --git a/lib/model/dailyTaskPlaning/comment_task_bottom_sheet.dart b/lib/model/dailyTaskPlaning/comment_task_bottom_sheet.dart index 39b0e48..2c4c435 100644 --- a/lib/model/dailyTaskPlaning/comment_task_bottom_sheet.dart +++ b/lib/model/dailyTaskPlaning/comment_task_bottom_sheet.dart @@ -58,6 +58,7 @@ class _CommentTaskBottomSheetState extends State data['assigned'] ?? ''; controller.basicValidator.getController('task_id')?.text = data['taskId'] ?? ''; + controller.basicValidator.getController('comment')?.clear(); WidgetsBinding.instance.addPostFrameCallback((_) { if (_scrollController.hasClients) { _scrollController.jumpTo(_scrollController.position.maxScrollExtent); diff --git a/lib/model/dailyTaskPlaning/report_task_bottom_sheet.dart b/lib/model/dailyTaskPlaning/report_task_bottom_sheet.dart index 134fd85..d4635ff 100644 --- a/lib/model/dailyTaskPlaning/report_task_bottom_sheet.dart +++ b/lib/model/dailyTaskPlaning/report_task_bottom_sheet.dart @@ -10,8 +10,8 @@ import 'package:marco/helpers/widgets/my_text_style.dart'; class ReportTaskBottomSheet extends StatefulWidget { final Map taskData; - - const ReportTaskBottomSheet({super.key, required this.taskData}); +final VoidCallback? onReportSuccess; + const ReportTaskBottomSheet({super.key, required this.taskData,this.onReportSuccess,}); @override State createState() => _ReportTaskBottomSheetState(); @@ -43,6 +43,8 @@ class _ReportTaskBottomSheetState extends State taskData['assigned'] ?? ''; controller.basicValidator.getController('task_id')?.text = taskData['taskId'] ?? ''; + controller.basicValidator.getController('completed_work')?.clear(); + controller.basicValidator.getController('comment')?.clear(); } @override @@ -222,8 +224,10 @@ class _ReportTaskBottomSheetState extends State 0, checklist: [], reportedDate: DateTime.now(), - - ); + ); + if (widget.onReportSuccess != null) { + widget.onReportSuccess!(); + } } }, elevation: 0, diff --git a/lib/routes.dart b/lib/routes.dart index dbb0f9a..55a14eb 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -5,15 +5,11 @@ import 'package:marco/view/auth/forgot_password_screen.dart'; import 'package:marco/view/auth/login_screen.dart'; import 'package:marco/view/auth/register_account_screen.dart'; import 'package:marco/view/auth/reset_password_screen.dart'; -// import 'package:marco/view/dashboard/ecommerce_screen.dart'; import 'package:marco/view/error_pages/coming_soon_screen.dart'; import 'package:marco/view/error_pages/error_404_screen.dart'; import 'package:marco/view/error_pages/error_500_screen.dart'; -// import 'package:marco/view/dashboard/attendance_screen.dart'; -// import 'package:marco/view/dashboard/attendanceScreen.dart'; import 'package:marco/view/dashboard/dashboard_screen.dart'; import 'package:marco/view/dashboard/add_employee_screen.dart'; -import 'package:marco/view/dashboard/employee_screen.dart'; import 'package:marco/view/dashboard/daily_task_screen.dart'; import 'package:marco/view/taskPlaning/report_task_screen.dart'; import 'package:marco/view/taskPlaning/comment_task_screen.dart'; @@ -33,7 +29,7 @@ getPageRoute() { var routes = [ GetPage( name: '/', - page: () => AttendanceScreen(), + page: () => DashboardScreen(), middlewares: [AuthMiddleware()]), // Dashboard GetPage( diff --git a/lib/view/dashboard/Attendence/attendance_screen.dart b/lib/view/dashboard/Attendence/attendance_screen.dart index c01d2ab..bd83b76 100644 --- a/lib/view/dashboard/Attendence/attendance_screen.dart +++ b/lib/view/dashboard/Attendence/attendance_screen.dart @@ -70,7 +70,6 @@ class _AttendanceScreenState extends State with UIMixin { "Filter", fontWeight: 600, ), - // Wrap with Tooltip and InkWell for interactive feedback Tooltip( message: 'Filter Project', child: InkWell( @@ -232,158 +231,148 @@ class _AttendanceScreenState extends State with UIMixin { ], ), ), - MyCard.bordered( - borderRadiusAll: 4, - border: Border.all(color: Colors.grey.withOpacity(0.2)), - shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom), - paddingAll: 8, - child: isLoading - ? Center(child: CircularProgressIndicator()) - : employees.isEmpty - ? Center( - child: MyText.bodySmall( - "No Employees Assigned to This Project", - fontWeight: 600, - ), - ) - : Column( - children: List.generate(employees.length, (index) { - final employee = employees[index]; - return Column( + if (isLoading) + const SizedBox( + height: 120, + child: Center(child: CircularProgressIndicator()), + ) + else if (employees.isEmpty) + SizedBox( + height: 120, + child: Center( + child: MyText.bodySmall( + "No Employees Assigned to This Project", + fontWeight: 600, + ), + ), + ) + else + MyCard.bordered( + borderRadiusAll: 4, + border: Border.all(color: Colors.grey.withOpacity(0.2)), + shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom), + paddingAll: 8, + child: Column( + children: List.generate(employees.length, (index) { + final employee = employees[index]; + return Column( + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 8), + child: MyContainer( + paddingAll: 5, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Padding( - padding: EdgeInsets.only(bottom: 8), - child: MyContainer( - paddingAll: 5, - child: Row( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Avatar( - firstName: employee.firstName, - lastName: employee.lastName, - size: 31, - ), - MySpacing.width(16), - Expanded( - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Row( - children: [ - MyText.bodyMedium( - employee.name, - fontWeight: 600, - overflow: - TextOverflow.ellipsis, - maxLines: 1, - ), - MySpacing.width(6), - MyText.bodySmall( - '(${employee.designation})', - fontWeight: 600, - overflow: - TextOverflow.ellipsis, - maxLines: 1, - color: Colors.grey[ - 700], // optional styling - ), - ], - ), - MySpacing.height(8), - (employee.checkIn != null || - employee.checkOut != null) - ? Row( - children: [ - if (employee.checkIn != - null) ...[ - Icon( - Icons - .arrow_circle_right, - size: 16, - color: - Colors.green), - MySpacing.width(4), - Expanded( - child: - MyText.bodySmall( - DateFormat( - 'hh:mm a') - .format(employee - .checkIn!), - fontWeight: 600, - overflow: - TextOverflow - .ellipsis, - ), - ), - MySpacing.width(16), - ], - if (employee.checkOut != - null) ...[ - Icon( - Icons - .arrow_circle_left, - size: 16, - color: Colors.red), - MySpacing.width(4), - Expanded( - child: - MyText.bodySmall( - DateFormat( - 'hh:mm a') - .format(employee - .checkOut!), - fontWeight: 600, - overflow: - TextOverflow - .ellipsis, - ), - ), - ], - ], - ) - : SizedBox.shrink(), - MySpacing.height(12), - Row( - mainAxisAlignment: - MainAxisAlignment.end, - children: [ - AttendanceActionButton( - employee: employee, - attendanceController: - attendanceController, - ), - if (employee.checkIn != - null) ...[ - MySpacing.width(8), - AttendanceLogViewButton( - employee: employee, - attendanceController: - attendanceController, - ), - ], - ], - ), - ], + Avatar( + firstName: employee.firstName, + lastName: employee.lastName, + size: 31, + ), + MySpacing.width(16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + MyText.bodyMedium( + employee.name, + fontWeight: 600, + overflow: TextOverflow.ellipsis, + maxLines: 1, ), - ), - ], - ), + MySpacing.width(6), + MyText.bodySmall( + '(${employee.designation})', + fontWeight: 600, + overflow: TextOverflow.ellipsis, + maxLines: 1, + color: Colors.grey[700], + ), + ], + ), + MySpacing.height(8), + (employee.checkIn != null || + employee.checkOut != null) + ? Row( + children: [ + if (employee.checkIn != null) ...[ + const Icon( + Icons.arrow_circle_right, + size: 16, + color: Colors.green), + MySpacing.width(4), + Expanded( + child: MyText.bodySmall( + DateFormat('hh:mm a') + .format( + employee.checkIn!), + fontWeight: 600, + overflow: + TextOverflow.ellipsis, + ), + ), + MySpacing.width(16), + ], + if (employee.checkOut != + null) ...[ + const Icon( + Icons.arrow_circle_left, + size: 16, + color: Colors.red), + MySpacing.width(4), + Expanded( + child: MyText.bodySmall( + DateFormat('hh:mm a') + .format( + employee.checkOut!), + fontWeight: 600, + overflow: + TextOverflow.ellipsis, + ), + ), + ], + ], + ) + : const SizedBox.shrink(), + MySpacing.height(12), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + AttendanceActionButton( + employee: employee, + attendanceController: + attendanceController, + ), + if (employee.checkIn != null) ...[ + MySpacing.width(8), + AttendanceLogViewButton( + employee: employee, + attendanceController: + attendanceController, + ), + ], + ], + ), + ], ), ), - if (index != employees.length - 1) - Divider( - color: Colors.grey.withOpacity(0.3), - thickness: 1, - height: 1, - ), ], - ); - }), + ), + ), ), - ), + if (index != employees.length - 1) + Divider( + color: Colors.grey.withOpacity(0.3), + thickness: 1, + height: 1, + ), + ], + ); + }), + ), + ), ], ); }); @@ -397,6 +386,7 @@ class _AttendanceScreenState extends State with UIMixin { final bDate = b.checkIn ?? DateTime(0); return bDate.compareTo(aDate); }); + return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -437,179 +427,176 @@ class _AttendanceScreenState extends State with UIMixin { ], ), ), - MyCard.bordered( - borderRadiusAll: 4, - border: Border.all(color: Colors.grey.withOpacity(0.2)), - shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom), - paddingAll: 8, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (attendanceController.isLoadingAttendanceLogs.value) - const Padding( - padding: EdgeInsets.symmetric(vertical: 32), - child: Center(child: CircularProgressIndicator()), - ) - else if (logs.isEmpty) - MyText.bodySmall( - "No Attendance Logs Found for this Project", - fontWeight: 600, - ) - else - Column( - children: List.generate(logs.length, (index) { - final employee = logs[index]; - final currentDate = employee.checkIn != null - ? DateFormat('dd MMM yyyy').format(employee.checkIn!) + if (attendanceController.isLoadingAttendanceLogs.value) + const SizedBox( + height: 120, + child: Center(child: CircularProgressIndicator()), + ) + else if (logs.isEmpty) + SizedBox( + height: 120, + child: Center( + child: MyText.bodySmall( + "No Attendance Logs Found for this Project", + fontWeight: 600, + ), + ), + ) + else + MyCard.bordered( + borderRadiusAll: 4, + border: Border.all(color: Colors.grey.withOpacity(0.2)), + shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom), + paddingAll: 8, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: List.generate(logs.length, (index) { + final employee = logs[index]; + final currentDate = employee.checkIn != null + ? DateFormat('dd MMM yyyy').format(employee.checkIn!) + : ''; + final previousDate = + index > 0 && logs[index - 1].checkIn != null + ? DateFormat('dd MMM yyyy') + .format(logs[index - 1].checkIn!) : ''; - final previousDate = - index > 0 && logs[index - 1].checkIn != null - ? DateFormat('dd MMM yyyy') - .format(logs[index - 1].checkIn!) - : ''; - final showDateHeader = - index == 0 || currentDate != previousDate; + final showDateHeader = + index == 0 || currentDate != previousDate; - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (showDateHeader) - Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: MyText.bodyMedium( - currentDate, - fontWeight: 700, + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (showDateHeader) + Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: MyText.bodyMedium( + currentDate, + fontWeight: 700, + ), + ), + Padding( + padding: const EdgeInsets.only(bottom: 8), + child: MyContainer( + paddingAll: 8, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Avatar( + firstName: employee.firstName, + lastName: employee.lastName, + size: 31, ), - ), - Padding( - padding: EdgeInsets.only(bottom: 8), - child: MyContainer( - paddingAll: 8, - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Avatar( - firstName: employee.firstName, - lastName: employee.lastName, - size: 31, - ), - MySpacing.width(16), - Expanded( - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, + MySpacing.width(16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( children: [ - Row( - children: [ - Flexible( - child: MyText.bodyMedium( - employee.name, - fontWeight: 600, - overflow: TextOverflow.ellipsis, - maxLines: 1, - ), - ), - MySpacing.width(6), - Flexible( - child: MyText.bodySmall( - '(${employee.designation})', - fontWeight: 600, - overflow: TextOverflow.ellipsis, - maxLines: 1, - color: Colors.grey[700], - ), - ), - ], + Flexible( + child: MyText.bodyMedium( + employee.name, + fontWeight: 600, + overflow: TextOverflow.ellipsis, + maxLines: 1, + ), ), - MySpacing.height(8), - (employee.checkIn != null || - employee.checkOut != null) - ? Row( - children: [ - if (employee.checkIn != - null) ...[ - Icon( - Icons - .arrow_circle_right, - size: 16, - color: Colors.green), - MySpacing.width(4), - Expanded( - child: MyText.bodySmall( - DateFormat('hh:mm a') - .format(employee - .checkIn!), - fontWeight: 600, - overflow: TextOverflow - .ellipsis, - ), - ), - MySpacing.width(16), - ], - if (employee.checkOut != - null) ...[ - Icon( - Icons.arrow_circle_left, - size: 16, - color: Colors.red), - MySpacing.width(4), - Expanded( - child: MyText.bodySmall( - DateFormat('hh:mm a') - .format(employee - .checkOut!), - fontWeight: 600, - overflow: TextOverflow - .ellipsis, - ), - ), - ], - ], - ) - : SizedBox.shrink(), - MySpacing.height(12), - Row( - mainAxisAlignment: - MainAxisAlignment.end, - children: [ - Flexible( - child: AttendanceActionButton( - employee: employee, - attendanceController: - attendanceController, - ), - ), - MySpacing.width(8), - Flexible( - child: AttendanceLogViewButton( - employee: employee, - attendanceController: - attendanceController, - ), - ), - ], + MySpacing.width(6), + Flexible( + child: MyText.bodySmall( + '(${employee.designation})', + fontWeight: 600, + overflow: TextOverflow.ellipsis, + maxLines: 1, + color: Colors.grey[700], + ), ), ], ), - ), - ], + MySpacing.height(8), + (employee.checkIn != null || + employee.checkOut != null) + ? Row( + children: [ + if (employee.checkIn != null) ...[ + const Icon( + Icons.arrow_circle_right, + size: 16, + color: Colors.green), + MySpacing.width(4), + Expanded( + child: MyText.bodySmall( + DateFormat('hh:mm a') + .format( + employee.checkIn!), + fontWeight: 600, + overflow: + TextOverflow.ellipsis, + ), + ), + MySpacing.width(16), + ], + if (employee.checkOut != + null) ...[ + const Icon( + Icons.arrow_circle_left, + size: 16, + color: Colors.red), + MySpacing.width(4), + Expanded( + child: MyText.bodySmall( + DateFormat('hh:mm a') + .format( + employee.checkOut!), + fontWeight: 600, + overflow: + TextOverflow.ellipsis, + ), + ), + ], + ], + ) + : const SizedBox.shrink(), + MySpacing.height(12), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Flexible( + child: AttendanceActionButton( + employee: employee, + attendanceController: + attendanceController, + ), + ), + MySpacing.width(8), + Flexible( + child: AttendanceLogViewButton( + employee: employee, + attendanceController: + attendanceController, + ), + ), + ], + ), + ], + ), ), - ), + ], ), - if (index != logs.length - 1) - Divider( - color: Colors.grey.withOpacity(0.3), - thickness: 1, - height: 1, - ), - ], - ); - }), - ), - ], + ), + ), + if (index != logs.length - 1) + Divider( + color: Colors.grey.withOpacity(0.3), + thickness: 1, + height: 1, + ), + ], + ); + }), + ), ), - ), ], ); }); @@ -628,151 +615,143 @@ class _AttendanceScreenState extends State with UIMixin { ), Obx(() { final employees = attendanceController.regularizationLogs; + if (attendanceController.isLoadingRegularizationLogs.value) { + return SizedBox( + height: 120, + child: const Center(child: CircularProgressIndicator()), + ); + } + if (employees.isEmpty) { + return SizedBox( + height: 120, + child: Center( + child: MyText.bodySmall( + "No Regularization Requests Found for this Project", + fontWeight: 600, + ), + ), + ); + } return MyCard.bordered( borderRadiusAll: 4, border: Border.all(color: Colors.grey.withOpacity(0.2)), shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom), paddingAll: 8, - child: attendanceController.isLoadingRegularizationLogs.value - ? const Padding( - padding: EdgeInsets.symmetric(vertical: 32.0), - child: Center(child: CircularProgressIndicator()), - ) - : employees.isEmpty - ? MyText.bodySmall( - "No Regularization Requests Found for this Project", - fontWeight: 600, - ) - : Column( - children: List.generate(employees.length, (index) { - final employee = employees[index]; - return Column( - children: [ - Padding( - padding: EdgeInsets.only(bottom: 8), - child: MyContainer( - paddingAll: 8, - child: Row( - crossAxisAlignment: - CrossAxisAlignment.start, + child: Column( + children: List.generate(employees.length, (index) { + final employee = employees[index]; + return Column( + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 8), + child: MyContainer( + paddingAll: 8, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Avatar( + firstName: employee.firstName, + lastName: employee.lastName, + size: 31, + ), + MySpacing.width(16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( children: [ - Avatar( - firstName: employee.firstName, - lastName: employee.lastName, - size: 31, + Flexible( + child: MyText.bodyMedium( + employee.name, + fontWeight: 600, + overflow: TextOverflow.ellipsis, + maxLines: 1, + ), ), - MySpacing.width(16), - Expanded( - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Row( - children: [ - Flexible( - child: MyText.bodyMedium( - employee.name, - fontWeight: 600, - overflow: - TextOverflow.ellipsis, - maxLines: 1, - ), - ), - MySpacing.width(6), - Flexible( - child: MyText.bodySmall( - '(${employee.role})', - fontWeight: 600, - overflow: - TextOverflow.ellipsis, - maxLines: 1, - color: Colors.grey[700], - ), - ), - ], - ), - MySpacing.height(8), - Row( - children: [ - if (employee.checkIn != - null) ...[ - Icon(Icons.arrow_circle_right, - size: 16, - color: Colors.green), - MySpacing.width(4), - Expanded( - child: MyText.bodySmall( - DateFormat('hh:mm a') - .format(employee - .checkIn!), - fontWeight: 600, - overflow: - TextOverflow.ellipsis, - ), - ), - MySpacing.width(16), - ], - if (employee.checkOut != - null) ...[ - Icon(Icons.arrow_circle_left, - size: 16, - color: Colors.red), - MySpacing.width(4), - Expanded( - child: MyText.bodySmall( - DateFormat('hh:mm a') - .format(employee - .checkOut!), - fontWeight: 600, - overflow: - TextOverflow.ellipsis, - ), - ), - ], - ], - ), - MySpacing.height(12), - Row( - mainAxisAlignment: - MainAxisAlignment.end, - children: [ - RegularizeActionButton( - attendanceController: - attendanceController, - log: employee, - uniqueLogKey: - employee.employeeId, - action: ButtonActions.approve, - ), - const SizedBox(width: 8), - RegularizeActionButton( - attendanceController: - attendanceController, - log: employee, - uniqueLogKey: - employee.employeeId, - action: ButtonActions.reject, - ), - ], - ) - ], + MySpacing.width(6), + Flexible( + child: MyText.bodySmall( + '(${employee.role})', + fontWeight: 600, + overflow: TextOverflow.ellipsis, + maxLines: 1, + color: Colors.grey[700], ), ), ], ), - ), + MySpacing.height(8), + Row( + children: [ + if (employee.checkIn != null) ...[ + const Icon(Icons.arrow_circle_right, + size: 16, color: Colors.green), + MySpacing.width(4), + Expanded( + child: MyText.bodySmall( + DateFormat('hh:mm a') + .format(employee.checkIn!), + fontWeight: 600, + overflow: TextOverflow.ellipsis, + ), + ), + MySpacing.width(16), + ], + if (employee.checkOut != null) ...[ + const Icon(Icons.arrow_circle_left, + size: 16, color: Colors.red), + MySpacing.width(4), + Expanded( + child: MyText.bodySmall( + DateFormat('hh:mm a') + .format(employee.checkOut!), + fontWeight: 600, + overflow: TextOverflow.ellipsis, + ), + ), + ], + ], + ), + MySpacing.height(12), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + RegularizeActionButton( + attendanceController: + attendanceController, + log: employee, + uniqueLogKey: employee.employeeId, + action: ButtonActions.approve, + ), + const SizedBox(width: 8), + RegularizeActionButton( + attendanceController: + attendanceController, + log: employee, + uniqueLogKey: employee.employeeId, + action: ButtonActions.reject, + ), + ], + ) + ], ), - if (index != employees.length - 1) - Divider( - color: Colors.grey.withOpacity(0.3), - thickness: 1, - height: 1, - ), - ], - ); - }), + ), + ], + ), ), + ), + if (index != employees.length - 1) + Divider( + color: Colors.grey.withOpacity(0.3), + thickness: 1, + height: 1, + ), + ], + ); + }), + ), ); }), ], diff --git a/lib/view/layouts/layout.dart b/lib/view/layouts/layout.dart index 7b09b45..b917f74 100644 --- a/lib/view/layouts/layout.dart +++ b/lib/view/layouts/layout.dart @@ -272,7 +272,9 @@ class Layout extends StatelessWidget { ), MyButton( tapTargetSize: MaterialTapTargetSize.shrinkWrap, - onPressed: () => {Get.offNamed('/auth/login')}, + onPressed: () async { + await LocalStorage.logout(); + }, borderRadiusAll: AppStyle.buttonRadius.medium, padding: MySpacing.xy(8, 4), splashColor: contentTheme.onBackground.withAlpha(20), diff --git a/lib/view/layouts/left_bar.dart b/lib/view/layouts/left_bar.dart index 5eb230f..3f066f3 100644 --- a/lib/view/layouts/left_bar.dart +++ b/lib/view/layouts/left_bar.dart @@ -172,13 +172,16 @@ class _LeftBarState extends State ), ), MyContainer( - onTap: () { - Get.offNamed('/auth/login'); + onTap: () async { + await LocalStorage.logout(); }, color: leftBarTheme.activeItemBackground, paddingAll: 8, - child: Icon(LucideIcons.log_out, - size: 16, color: leftBarTheme.activeItemColor), + child: Icon( + LucideIcons.log_out, + size: 16, + color: leftBarTheme.activeItemColor, + ), ) ], ), diff --git a/lib/view/taskPlaning/daily_progress.dart b/lib/view/taskPlaning/daily_progress.dart index 4bb7692..ba5cc4f 100644 --- a/lib/view/taskPlaning/daily_progress.dart +++ b/lib/view/taskPlaning/daily_progress.dart @@ -468,11 +468,16 @@ class _DailyProgressReportScreenState extends State top: Radius.circular( 16)), ), - builder: (_) => Padding( - padding: MediaQuery.of(context) + builder: (BuildContext ctx) => + Padding( + padding: MediaQuery.of(ctx) .viewInsets, child: ReportTaskBottomSheet( - taskData: taskData), + taskData: taskData, + onReportSuccess: () { + _refreshData(); + }, + ), ), ); }, -- 2.43.0