Refactor logging implementation across controllers and services
- Replaced instances of the Logger package with a custom appLogger for consistent logging. - Introduced app_logger.dart to manage logging with file output and storage permissions. - Updated all controllers (e.g., DashboardController, EmployeesScreenController, etc.) to use appLogger for logging messages. - Ensured that logging messages are appropriately categorized (info, warning, error) throughout the application. - Implemented a file logging mechanism to store logs in a designated directory. - Cleaned up old log files to maintain only the most recent logs.
This commit is contained in:
parent
ef60677c98
commit
e6d05e247e
@ -3,6 +3,9 @@
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS"/>
|
||||
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
|
||||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
|
||||
|
||||
|
||||
|
@ -5,12 +5,16 @@ import 'package:marco/helpers/services/auth_service.dart';
|
||||
import 'package:marco/helpers/widgets/my_form_validator.dart';
|
||||
import 'package:marco/helpers/widgets/my_validators.dart';
|
||||
import 'package:marco/helpers/widgets/my_snackbar.dart';
|
||||
import 'package:marco/helpers/services/app_logger.dart';
|
||||
import 'package:marco/helpers/services/storage/local_storage.dart';
|
||||
|
||||
class ForgotPasswordController extends MyController {
|
||||
MyFormValidator basicValidator = MyFormValidator();
|
||||
bool showPassword = false;
|
||||
final MyFormValidator basicValidator = MyFormValidator();
|
||||
final RxBool isLoading = false.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
basicValidator.addField(
|
||||
'email',
|
||||
required: true,
|
||||
@ -18,49 +22,51 @@ class ForgotPasswordController extends MyController {
|
||||
validators: [MyEmailValidator()],
|
||||
controller: TextEditingController(text: "demo@example.com"),
|
||||
);
|
||||
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> onLogin() async {
|
||||
if (basicValidator.validateForm()) {
|
||||
update();
|
||||
var errors = await AuthService.loginUser(basicValidator.getData());
|
||||
if (errors != null) {
|
||||
basicValidator.validateForm();
|
||||
basicValidator.clearErrors();
|
||||
}
|
||||
Get.toNamed('/auth/reset_password');
|
||||
update();
|
||||
Future<void> onForgotPassword() async {
|
||||
if (!basicValidator.validateForm()) return;
|
||||
|
||||
isLoading.value = true;
|
||||
final data = basicValidator.getData();
|
||||
final email = data['email']?.toString() ?? '';
|
||||
|
||||
try {
|
||||
appLogger.i("Forgot password requested for: $email");
|
||||
final result = await AuthService.forgotPassword(email);
|
||||
|
||||
if (result == null) {
|
||||
// Success case
|
||||
showAppSnackbar(
|
||||
title: "Success",
|
||||
message: "Password reset link has been sent.",
|
||||
type: SnackbarType.success,
|
||||
);
|
||||
await LocalStorage.logout();
|
||||
} else {
|
||||
// Failure case with error map
|
||||
final errorMessage = result['error'] ?? "Failed to send reset link. Please try again.";
|
||||
showAppSnackbar(
|
||||
title: "Failed",
|
||||
message: errorMessage,
|
||||
type: SnackbarType.error,
|
||||
);
|
||||
appLogger.w("Failed to send reset password email for $email: $errorMessage");
|
||||
}
|
||||
}
|
||||
|
||||
/// New: Forgot password function
|
||||
Future<void> onForgotPassword() async {
|
||||
if (basicValidator.validateForm()) {
|
||||
update();
|
||||
final data = basicValidator.getData();
|
||||
final email = data['email']?.toString() ?? '';
|
||||
final result = await AuthService.forgotPassword(email);
|
||||
|
||||
if (result != null) {
|
||||
showAppSnackbar(
|
||||
title: "Success",
|
||||
message: "Your password reset link was sent.",
|
||||
type: SnackbarType.success,
|
||||
);
|
||||
} else {
|
||||
showAppSnackbar(
|
||||
title: "Success",
|
||||
message: "Your password reset link was sent.",
|
||||
type: SnackbarType.success,
|
||||
);
|
||||
}
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void gotoLogIn() {
|
||||
Get.toNamed('/auth/login-option');
|
||||
} catch (e, stacktrace) {
|
||||
appLogger.e("Error during forgot password", error: e, stackTrace: stacktrace);
|
||||
showAppSnackbar(
|
||||
title: "Error",
|
||||
message: "Something went wrong. Please try again later.",
|
||||
type: SnackbarType.error,
|
||||
);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void gotoLogIn() {
|
||||
Get.offAllNamed('/auth/login-option');
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ import 'package:marco/helpers/widgets/my_form_validator.dart';
|
||||
import 'package:marco/helpers/widgets/my_validators.dart';
|
||||
import 'package:marco/helpers/services/storage/local_storage.dart';
|
||||
import 'package:marco/helpers/widgets/my_snackbar.dart';
|
||||
import 'package:marco/helpers/services/app_logger.dart'; // <-- logging
|
||||
|
||||
class LoginController extends MyController {
|
||||
final MyFormValidator basicValidator = MyFormValidator();
|
||||
|
||||
@ -51,40 +53,38 @@ class LoginController extends MyController {
|
||||
|
||||
isLoading.value = true;
|
||||
|
||||
final errors = await AuthService.loginUser(basicValidator.getData());
|
||||
try {
|
||||
final loginData = basicValidator.getData();
|
||||
appLogger.i("Attempting login for user: ${loginData['username']}");
|
||||
|
||||
if (errors != null) {
|
||||
showAppSnackbar(
|
||||
title: "Login Failed",
|
||||
message: "Username or password is incorrect",
|
||||
type: SnackbarType.error,
|
||||
);
|
||||
final errors = await AuthService.loginUser(loginData);
|
||||
|
||||
basicValidator.addErrors(errors);
|
||||
basicValidator.validateForm();
|
||||
basicValidator.clearErrors();
|
||||
} else {
|
||||
await _handleRememberMe();
|
||||
final bool isMpinEnabled = LocalStorage.getIsMpin();
|
||||
print('MPIN Enabled? $isMpinEnabled');
|
||||
if (errors != null) {
|
||||
appLogger.w("Login failed: $errors");
|
||||
|
||||
if (isMpinEnabled) {
|
||||
Get.toNamed('/home');
|
||||
showAppSnackbar(
|
||||
title: "Login Failed",
|
||||
message: "Username or password is incorrect",
|
||||
type: SnackbarType.error,
|
||||
);
|
||||
|
||||
basicValidator.addErrors(errors);
|
||||
basicValidator.validateForm();
|
||||
basicValidator.clearErrors();
|
||||
} else {
|
||||
await _handleRememberMe();
|
||||
appLogger.i("Login successful: ${loginData['username']}");
|
||||
Get.toNamed('/home');
|
||||
}
|
||||
}
|
||||
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
void handlePostLoginNavigation() {
|
||||
final bool isMpinEnabled = LocalStorage.getIsMpin();
|
||||
|
||||
if (isMpinEnabled) {
|
||||
Get.offAllNamed('/home');
|
||||
} else {
|
||||
Get.offAllNamed('/home');
|
||||
} catch (e, stacktrace) {
|
||||
appLogger.e("Exception during login", error: e, stackTrace: stacktrace);
|
||||
showAppSnackbar(
|
||||
title: "Login Error",
|
||||
message: "An unexpected error occurred",
|
||||
type: SnackbarType.error,
|
||||
);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,6 +99,7 @@ class LoginController extends MyController {
|
||||
await LocalStorage.removeToken('username');
|
||||
await LocalStorage.removeToken('password');
|
||||
await LocalStorage.setBool('remember_me', false);
|
||||
basicValidator.clearErrors();
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,4 +124,3 @@ class LoginController extends MyController {
|
||||
Get.offAndToNamed('/auth/register_account');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
import 'package:marco/helpers/services/auth_service.dart';
|
||||
import 'package:marco/helpers/services/storage/local_storage.dart';
|
||||
import 'package:marco/helpers/widgets/my_form_validator.dart';
|
||||
import 'package:marco/helpers/widgets/my_snackbar.dart';
|
||||
import 'package:marco/view/dashboard/dashboard_screen.dart';
|
||||
import 'package:marco/helpers/services/app_logger.dart';
|
||||
|
||||
class MPINController extends GetxController {
|
||||
final Logger logger = Logger();
|
||||
|
||||
final MyFormValidator basicValidator = MyFormValidator();
|
||||
final isNewUser = false.obs;
|
||||
@ -26,11 +25,11 @@ class MPINController extends GetxController {
|
||||
super.onInit();
|
||||
final bool hasMpin = LocalStorage.getIsMpin();
|
||||
isNewUser.value = !hasMpin;
|
||||
logger.i("[MPINController] onInit called. isNewUser: ${isNewUser.value}");
|
||||
appLogger.i("[MPINController] onInit called. isNewUser: ${isNewUser.value}");
|
||||
}
|
||||
|
||||
void onDigitChanged(String value, int index, {bool isRetype = false}) {
|
||||
logger.i(
|
||||
appLogger.i(
|
||||
"[MPINController] onDigitChanged -> index: $index, value: $value, isRetype: $isRetype");
|
||||
final nodes = isRetype ? retypeFocusNodes : focusNodes;
|
||||
if (value.isNotEmpty && index < 5) {
|
||||
@ -41,15 +40,15 @@ class MPINController extends GetxController {
|
||||
}
|
||||
|
||||
Future<void> onSubmitMPIN() async {
|
||||
logger.i("[MPINController] onSubmitMPIN triggered");
|
||||
appLogger.i("[MPINController] onSubmitMPIN triggered");
|
||||
|
||||
if (!formKey.currentState!.validate()) {
|
||||
logger.w("[MPINController] Form validation failed");
|
||||
appLogger.w("[MPINController] Form validation failed");
|
||||
return;
|
||||
}
|
||||
|
||||
final enteredMPIN = digitControllers.map((c) => c.text).join();
|
||||
logger.i("[MPINController] Entered MPIN: $enteredMPIN");
|
||||
appLogger.i("[MPINController] Entered MPIN: $enteredMPIN");
|
||||
|
||||
if (enteredMPIN.length < 6) {
|
||||
_showError("Please enter all 6 digits.");
|
||||
@ -58,7 +57,7 @@ class MPINController extends GetxController {
|
||||
|
||||
if (isNewUser.value) {
|
||||
final retypeMPIN = retypeControllers.map((c) => c.text).join();
|
||||
logger.i("[MPINController] Retyped MPIN: $retypeMPIN");
|
||||
appLogger.i("[MPINController] Retyped MPIN: $retypeMPIN");
|
||||
|
||||
if (retypeMPIN.length < 6) {
|
||||
_showError("Please enter all 6 digits in Retype MPIN.");
|
||||
@ -72,11 +71,11 @@ class MPINController extends GetxController {
|
||||
return;
|
||||
}
|
||||
|
||||
logger.i("[MPINController] MPINs matched. Proceeding to generate MPIN.");
|
||||
appLogger.i("[MPINController] MPINs matched. Proceeding to generate MPIN.");
|
||||
final bool success = await generateMPIN(mpin: enteredMPIN);
|
||||
|
||||
if (success) {
|
||||
logger.i("[MPINController] MPIN generation successful.");
|
||||
appLogger.i("[MPINController] MPIN generation successful.");
|
||||
showAppSnackbar(
|
||||
title: "Success",
|
||||
message: "MPIN generated successfully. Please login again.",
|
||||
@ -84,32 +83,32 @@ class MPINController extends GetxController {
|
||||
);
|
||||
await LocalStorage.logout();
|
||||
} else {
|
||||
logger.w("[MPINController] MPIN generation failed.");
|
||||
appLogger.w("[MPINController] MPIN generation failed.");
|
||||
clearFields();
|
||||
clearRetypeFields();
|
||||
}
|
||||
} else {
|
||||
logger.i("[MPINController] Existing user. Proceeding to verify MPIN.");
|
||||
appLogger.i("[MPINController] Existing user. Proceeding to verify MPIN.");
|
||||
await verifyMPIN();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> onForgotMPIN() async {
|
||||
logger.i("[MPINController] onForgotMPIN called");
|
||||
appLogger.i("[MPINController] onForgotMPIN called");
|
||||
isNewUser.value = true;
|
||||
clearFields();
|
||||
clearRetypeFields();
|
||||
}
|
||||
|
||||
void switchToEnterMPIN() {
|
||||
logger.i("[MPINController] switchToEnterMPIN called");
|
||||
appLogger.i("[MPINController] switchToEnterMPIN called");
|
||||
isNewUser.value = false;
|
||||
clearFields();
|
||||
clearRetypeFields();
|
||||
}
|
||||
|
||||
void _showError(String message) {
|
||||
logger.e("[MPINController] ERROR: $message");
|
||||
appLogger.e("[MPINController] ERROR: $message");
|
||||
showAppSnackbar(
|
||||
title: "Error",
|
||||
message: message,
|
||||
@ -119,7 +118,7 @@ class MPINController extends GetxController {
|
||||
|
||||
void _navigateToDashboard({String? message}) {
|
||||
if (message != null) {
|
||||
logger
|
||||
appLogger
|
||||
.i("[MPINController] Navigating to Dashboard with message: $message");
|
||||
showAppSnackbar(
|
||||
title: "Success",
|
||||
@ -131,7 +130,7 @@ class MPINController extends GetxController {
|
||||
}
|
||||
|
||||
void clearFields() {
|
||||
logger.i("[MPINController] clearFields called");
|
||||
appLogger.i("[MPINController] clearFields called");
|
||||
for (final c in digitControllers) {
|
||||
c.clear();
|
||||
}
|
||||
@ -139,7 +138,7 @@ class MPINController extends GetxController {
|
||||
}
|
||||
|
||||
void clearRetypeFields() {
|
||||
logger.i("[MPINController] clearRetypeFields called");
|
||||
appLogger.i("[MPINController] clearRetypeFields called");
|
||||
for (final c in retypeControllers) {
|
||||
c.clear();
|
||||
}
|
||||
@ -148,7 +147,7 @@ class MPINController extends GetxController {
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
logger.i("[MPINController] onClose called");
|
||||
appLogger.i("[MPINController] onClose called");
|
||||
for (final controller in digitControllers) {
|
||||
controller.dispose();
|
||||
}
|
||||
@ -169,7 +168,7 @@ class MPINController extends GetxController {
|
||||
}) async {
|
||||
try {
|
||||
isLoading.value = true;
|
||||
logger.i("[MPINController] generateMPIN started for MPIN: $mpin");
|
||||
appLogger.i("[MPINController] generateMPIN started for MPIN: $mpin");
|
||||
|
||||
final employeeInfo = LocalStorage.getEmployeeInfo();
|
||||
final String? employeeId = employeeInfo?.id;
|
||||
@ -180,7 +179,7 @@ class MPINController extends GetxController {
|
||||
return false;
|
||||
}
|
||||
|
||||
logger.i(
|
||||
appLogger.i(
|
||||
"[MPINController] Calling AuthService.generateMpin for employeeId: $employeeId");
|
||||
|
||||
final response = await AuthService.generateMpin(
|
||||
@ -191,7 +190,7 @@ class MPINController extends GetxController {
|
||||
isLoading.value = false;
|
||||
|
||||
if (response == null) {
|
||||
logger.i("[MPINController] MPIN generated successfully");
|
||||
appLogger.i("[MPINController] MPIN generated successfully");
|
||||
|
||||
showAppSnackbar(
|
||||
title: "Success",
|
||||
@ -203,7 +202,7 @@ class MPINController extends GetxController {
|
||||
|
||||
return true;
|
||||
} else {
|
||||
logger.w(
|
||||
appLogger.w(
|
||||
"[MPINController] MPIN generation returned error response: $response");
|
||||
showAppSnackbar(
|
||||
title: "MPIN Generation Failed",
|
||||
@ -218,16 +217,16 @@ class MPINController extends GetxController {
|
||||
} catch (e) {
|
||||
isLoading.value = false;
|
||||
_showError("Failed to generate MPIN: $e");
|
||||
logger.e("[MPINController] Exception in generateMPIN: $e");
|
||||
appLogger.e("[MPINController] Exception in generateMPIN: $e");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> verifyMPIN() async {
|
||||
logger.i("[MPINController] verifyMPIN triggered");
|
||||
appLogger.i("[MPINController] verifyMPIN triggered");
|
||||
|
||||
final enteredMPIN = digitControllers.map((c) => c.text).join();
|
||||
logger.i("[MPINController] Entered MPIN: $enteredMPIN");
|
||||
appLogger.i("[MPINController] Entered MPIN: $enteredMPIN");
|
||||
|
||||
if (enteredMPIN.length < 6) {
|
||||
_showError("Please enter all 6 digits.");
|
||||
@ -252,7 +251,7 @@ class MPINController extends GetxController {
|
||||
isLoading.value = false;
|
||||
|
||||
if (response == null) {
|
||||
logger.i("[MPINController] MPIN verified successfully.");
|
||||
appLogger.i("[MPINController] MPIN verified successfully.");
|
||||
|
||||
// Set mpin_verified to true in local storage here:
|
||||
await LocalStorage.setBool('mpin_verified', true);
|
||||
@ -265,7 +264,7 @@ class MPINController extends GetxController {
|
||||
_navigateToDashboard();
|
||||
} else {
|
||||
final errorMessage = response["error"] ?? "Invalid MPIN";
|
||||
logger.w("[MPINController] MPIN verification failed: $errorMessage");
|
||||
appLogger.w("[MPINController] MPIN verification failed: $errorMessage");
|
||||
showAppSnackbar(
|
||||
title: "Error",
|
||||
message: errorMessage,
|
||||
@ -277,7 +276,7 @@ class MPINController extends GetxController {
|
||||
} catch (e) {
|
||||
isLoading.value = false;
|
||||
final error = "Failed to verify MPIN: $e";
|
||||
logger.e("[MPINController] Exception in verifyMPIN: $error");
|
||||
appLogger.e("[MPINController] Exception in verifyMPIN: $error");
|
||||
showAppSnackbar(
|
||||
title: "Error",
|
||||
message: "Something went wrong. Please try again.",
|
||||
|
@ -4,6 +4,8 @@ import 'package:get/get.dart';
|
||||
import 'package:marco/helpers/widgets/my_snackbar.dart';
|
||||
import 'package:marco/helpers/services/auth_service.dart';
|
||||
import 'package:marco/helpers/services/storage/local_storage.dart';
|
||||
import 'package:marco/helpers/services/app_logger.dart';
|
||||
|
||||
class OTPController extends GetxController {
|
||||
final formKey = GlobalKey<FormState>();
|
||||
|
||||
@ -23,6 +25,7 @@ class OTPController extends GetxController {
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
timer.value = 0;
|
||||
appLogger.i("[OTPController] Initialized");
|
||||
}
|
||||
|
||||
@override
|
||||
@ -35,15 +38,18 @@ class OTPController extends GetxController {
|
||||
for (final node in focusNodes) {
|
||||
node.dispose();
|
||||
}
|
||||
appLogger.i("[OTPController] Disposed");
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
Future<bool> _sendOTP(String email) async {
|
||||
appLogger.i("[OTPController] Sending OTP to $email");
|
||||
final result = await AuthService.generateOtp(email);
|
||||
if (result == null) {
|
||||
debugPrint('OTP sent to $email');
|
||||
appLogger.i("[OTPController] OTP sent successfully to $email");
|
||||
return true;
|
||||
} else {
|
||||
appLogger.w("[OTPController] OTP send failed: ${result['error']}");
|
||||
showAppSnackbar(
|
||||
title: "Error",
|
||||
message: result['error'] ?? "Failed to send OTP",
|
||||
@ -55,8 +61,10 @@ class OTPController extends GetxController {
|
||||
|
||||
Future<void> sendOTP() async {
|
||||
final userEmail = emailController.text.trim();
|
||||
appLogger.i("[OTPController] sendOTP called for $userEmail");
|
||||
|
||||
if (!_validateEmail(userEmail)) {
|
||||
appLogger.w("[OTPController] Invalid email format: $userEmail");
|
||||
showAppSnackbar(
|
||||
title: "Error",
|
||||
message: "Please enter a valid email address",
|
||||
@ -81,8 +89,9 @@ class OTPController extends GetxController {
|
||||
|
||||
Future<void> onResendOTP() async {
|
||||
if (isResending.value) return;
|
||||
isResending.value = true;
|
||||
appLogger.i("[OTPController] Resending OTP to ${email.value}");
|
||||
|
||||
isResending.value = true;
|
||||
_clearOTPFields();
|
||||
|
||||
final success = await _sendOTP(email.value);
|
||||
@ -94,6 +103,7 @@ class OTPController extends GetxController {
|
||||
}
|
||||
|
||||
void onOTPChanged(String value, int index) {
|
||||
appLogger.d("[OTPController] OTP field changed: index=$index, value=$value");
|
||||
if (value.isNotEmpty) {
|
||||
if (index < otpControllers.length - 1) {
|
||||
focusNodes[index + 1].requestFocus();
|
||||
@ -109,6 +119,7 @@ class OTPController extends GetxController {
|
||||
|
||||
Future<void> verifyOTP() async {
|
||||
final enteredOTP = otpControllers.map((c) => c.text).join();
|
||||
appLogger.i("[OTPController] Verifying OTP: $enteredOTP for email: ${email.value}");
|
||||
|
||||
final result = await AuthService.verifyOtp(
|
||||
email: email.value,
|
||||
@ -116,13 +127,14 @@ class OTPController extends GetxController {
|
||||
);
|
||||
|
||||
if (result == null) {
|
||||
appLogger.i("[OTPController] OTP verified successfully");
|
||||
showAppSnackbar(
|
||||
title: "Success",
|
||||
message: "OTP verified successfully",
|
||||
type: SnackbarType.success,
|
||||
);
|
||||
final bool isMpinEnabled = LocalStorage.getIsMpin();
|
||||
print('MPIN Enabled? $isMpinEnabled');
|
||||
appLogger.i("[OTPController] MPIN Enabled: $isMpinEnabled");
|
||||
|
||||
if (isMpinEnabled) {
|
||||
Get.offAllNamed('/home');
|
||||
@ -130,15 +142,18 @@ class OTPController extends GetxController {
|
||||
Get.offAllNamed('/home');
|
||||
}
|
||||
} else {
|
||||
final error = result['error'] ?? "Failed to verify OTP";
|
||||
appLogger.w("[OTPController] OTP verification failed: $error");
|
||||
showAppSnackbar(
|
||||
title: "Error",
|
||||
message: result['error'] ?? "Failed to verify OTP",
|
||||
message: error,
|
||||
type: SnackbarType.error,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void _clearOTPFields() {
|
||||
appLogger.d("[OTPController] Clearing OTP input fields");
|
||||
for (final controller in otpControllers) {
|
||||
controller.clear();
|
||||
}
|
||||
@ -146,6 +161,7 @@ class OTPController extends GetxController {
|
||||
}
|
||||
|
||||
void _startTimer() {
|
||||
appLogger.i("[OTPController] Starting resend timer");
|
||||
timer.value = 60;
|
||||
_countdownTimer?.cancel();
|
||||
_countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||
@ -158,6 +174,8 @@ class OTPController extends GetxController {
|
||||
}
|
||||
|
||||
void resetForChangeEmail() {
|
||||
appLogger.i("[OTPController] Resetting OTP form for change email");
|
||||
|
||||
isOTPSent.value = false;
|
||||
email.value = '';
|
||||
emailController.clear();
|
||||
|
@ -3,16 +3,17 @@ import 'package:get/get.dart';
|
||||
import 'package:marco/controller/my_controller.dart';
|
||||
import 'package:marco/helpers/widgets/my_form_validator.dart';
|
||||
import 'package:marco/helpers/widgets/my_validators.dart';
|
||||
|
||||
import 'package:marco/helpers/services/auth_service.dart';
|
||||
import 'package:marco/helpers/services/auth_service.dart';
|
||||
import 'package:marco/helpers/services/app_logger.dart';
|
||||
|
||||
class RegisterAccountController extends MyController {
|
||||
MyFormValidator basicValidator = MyFormValidator();
|
||||
|
||||
bool showPassword = false;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
appLogger.i("[RegisterAccountController] onInit called");
|
||||
|
||||
basicValidator.addField(
|
||||
'email',
|
||||
required: true,
|
||||
@ -38,29 +39,39 @@ class RegisterAccountController extends MyController {
|
||||
validators: [MyLengthValidator(min: 6, max: 10)],
|
||||
controller: TextEditingController(),
|
||||
);
|
||||
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> onLogin() async {
|
||||
if (basicValidator.validateForm()) {
|
||||
update();
|
||||
appLogger.i("[RegisterAccountController] Submitting registration data: ${basicValidator.getData()}");
|
||||
|
||||
var errors = await AuthService.loginUser(basicValidator.getData());
|
||||
if (errors != null) {
|
||||
appLogger.w("[RegisterAccountController] Login errors: $errors");
|
||||
basicValidator.addErrors(errors);
|
||||
basicValidator.validateForm();
|
||||
basicValidator.clearErrors();
|
||||
}
|
||||
|
||||
appLogger.i("[RegisterAccountController] Redirecting to /starter");
|
||||
Get.toNamed('/starter');
|
||||
update();
|
||||
} else {
|
||||
appLogger.w("[RegisterAccountController] Validation failed");
|
||||
}
|
||||
}
|
||||
|
||||
void onChangeShowPassword() {
|
||||
showPassword = !showPassword;
|
||||
appLogger.i("[RegisterAccountController] showPassword toggled: $showPassword");
|
||||
update();
|
||||
}
|
||||
|
||||
void gotoLogin() {
|
||||
appLogger.i("[RegisterAccountController] Navigating to /auth/login-option");
|
||||
Get.toNamed('/auth/login-option');
|
||||
}
|
||||
}
|
||||
|
@ -4,56 +4,68 @@ import 'package:marco/controller/my_controller.dart';
|
||||
import 'package:marco/helpers/services/auth_service.dart';
|
||||
import 'package:marco/helpers/widgets/my_form_validator.dart';
|
||||
import 'package:marco/helpers/widgets/my_validators.dart';
|
||||
import 'package:marco/helpers/services/app_logger.dart';
|
||||
|
||||
class ResetPasswordController extends MyController {
|
||||
MyFormValidator basicValidator = MyFormValidator();
|
||||
bool showPassword = false;
|
||||
|
||||
bool confirmPassword = false;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
appLogger.i("[ResetPasswordController] onInit called");
|
||||
|
||||
basicValidator.addField(
|
||||
'password',
|
||||
required: true,
|
||||
validators: [
|
||||
MyLengthValidator(min: 6, max: 10),
|
||||
],
|
||||
validators: [MyLengthValidator(min: 6, max: 10)],
|
||||
controller: TextEditingController(),
|
||||
);
|
||||
|
||||
basicValidator.addField(
|
||||
'confirm_password',
|
||||
required: true,
|
||||
label: "Confirm password",
|
||||
validators: [
|
||||
MyLengthValidator(min: 6, max: 10),
|
||||
],
|
||||
validators: [MyLengthValidator(min: 6, max: 10)],
|
||||
controller: TextEditingController(),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> onResetPassword() async {
|
||||
appLogger.i("[ResetPasswordController] onResetPassword triggered");
|
||||
|
||||
if (basicValidator.validateForm()) {
|
||||
final data = basicValidator.getData();
|
||||
appLogger.i("[ResetPasswordController] Form data: $data");
|
||||
|
||||
update();
|
||||
var errors = await AuthService.loginUser(basicValidator.getData());
|
||||
var errors = await AuthService.loginUser(data);
|
||||
|
||||
if (errors != null) {
|
||||
appLogger.w("[ResetPasswordController] Received errors: $errors");
|
||||
basicValidator.addErrors(errors);
|
||||
basicValidator.validateForm();
|
||||
basicValidator.clearErrors();
|
||||
}
|
||||
|
||||
appLogger.i("[ResetPasswordController] Navigating to /home");
|
||||
Get.toNamed('/home');
|
||||
update();
|
||||
} else {
|
||||
appLogger.w("[ResetPasswordController] Form validation failed");
|
||||
}
|
||||
}
|
||||
|
||||
void onChangeShowPassword() {
|
||||
showPassword = !showPassword;
|
||||
appLogger.i("[ResetPasswordController] showPassword toggled: $showPassword");
|
||||
update();
|
||||
}
|
||||
|
||||
void onConfirmPassword() {
|
||||
confirmPassword = !confirmPassword;
|
||||
appLogger.i("[ResetPasswordController] confirmPassword toggled: $confirmPassword");
|
||||
update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,10 +3,10 @@ import 'package:flutter/material.dart';
|
||||
import 'package:marco/controller/my_controller.dart';
|
||||
import 'package:marco/helpers/widgets/my_form_validator.dart';
|
||||
import 'package:marco/helpers/services/api_service.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
import 'package:marco/helpers/widgets/my_snackbar.dart';
|
||||
import 'package:flutter_contacts/flutter_contacts.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:marco/helpers/services/app_logger.dart';
|
||||
|
||||
enum Gender {
|
||||
male,
|
||||
@ -16,7 +16,6 @@ enum Gender {
|
||||
const Gender();
|
||||
}
|
||||
|
||||
final Logger logger = Logger();
|
||||
|
||||
class AddEmployeeController extends MyController {
|
||||
List<PlatformFile> files = [];
|
||||
@ -67,7 +66,7 @@ class AddEmployeeController extends MyController {
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
logger.i("Initializing AddEmployeeController...");
|
||||
appLogger.i("Initializing AddEmployeeController...");
|
||||
_initializeFields();
|
||||
fetchRoles();
|
||||
}
|
||||
@ -91,41 +90,41 @@ class AddEmployeeController extends MyController {
|
||||
required: true,
|
||||
controller: TextEditingController(),
|
||||
);
|
||||
logger.i("Fields initialized for first_name, phone_number, last_name.");
|
||||
appLogger.i("Fields initialized for first_name, phone_number, last_name.");
|
||||
}
|
||||
|
||||
void onGenderSelected(Gender? gender) {
|
||||
selectedGender = gender;
|
||||
logger.i("Gender selected: ${gender?.name}");
|
||||
appLogger.i("Gender selected: ${gender?.name}");
|
||||
update();
|
||||
}
|
||||
|
||||
Future<void> fetchRoles() async {
|
||||
logger.i("Fetching roles...");
|
||||
appLogger.i("Fetching roles...");
|
||||
try {
|
||||
final result = await ApiService.getRoles();
|
||||
if (result != null) {
|
||||
roles = List<Map<String, dynamic>>.from(result);
|
||||
logger.i("Roles fetched successfully.");
|
||||
appLogger.i("Roles fetched successfully.");
|
||||
update();
|
||||
} else {
|
||||
logger.e("Failed to fetch roles: null result");
|
||||
appLogger.e("Failed to fetch roles: null result");
|
||||
}
|
||||
} catch (e, st) {
|
||||
logger.e("Error fetching roles: $e", error: e, stackTrace: st);
|
||||
appLogger.e("Error fetching roles: $e", error: e, stackTrace: st);
|
||||
}
|
||||
}
|
||||
|
||||
void onRoleSelected(String? roleId) {
|
||||
selectedRoleId = roleId;
|
||||
logger.i("Role selected: $roleId");
|
||||
appLogger.i("Role selected: $roleId");
|
||||
update();
|
||||
}
|
||||
|
||||
Future<bool> createEmployees() async {
|
||||
logger.i("Starting employee creation...");
|
||||
appLogger.i("Starting employee creation...");
|
||||
if (selectedGender == null || selectedRoleId == null) {
|
||||
logger.w("Missing gender or role.");
|
||||
appLogger.w("Missing gender or role.");
|
||||
showAppSnackbar(
|
||||
title: "Missing Fields",
|
||||
message: "Please select both Gender and Role.",
|
||||
@ -139,7 +138,7 @@ class AddEmployeeController extends MyController {
|
||||
final phoneNumber =
|
||||
basicValidator.getController("phone_number")?.text.trim();
|
||||
|
||||
logger.i(
|
||||
appLogger.i(
|
||||
"Creating employee with Name: $firstName $lastName, Phone: $phoneNumber, Gender: ${selectedGender!.name}");
|
||||
|
||||
try {
|
||||
@ -152,7 +151,7 @@ class AddEmployeeController extends MyController {
|
||||
);
|
||||
|
||||
if (response == true) {
|
||||
logger.i("Employee created successfully.");
|
||||
appLogger.i("Employee created successfully.");
|
||||
showAppSnackbar(
|
||||
title: "Success",
|
||||
message: "Employee created successfully!",
|
||||
@ -160,10 +159,10 @@ class AddEmployeeController extends MyController {
|
||||
);
|
||||
return true;
|
||||
} else {
|
||||
logger.e("Failed to create employee (response false).");
|
||||
appLogger.e("Failed to create employee (response false).");
|
||||
}
|
||||
} catch (e, st) {
|
||||
logger.e("Error creating employee: $e", error: e, stackTrace: st);
|
||||
appLogger.e("Error creating employee: $e", error: e, stackTrace: st);
|
||||
}
|
||||
|
||||
showAppSnackbar(
|
||||
@ -279,7 +278,7 @@ class AddEmployeeController extends MyController {
|
||||
|
||||
update();
|
||||
} catch (e, st) {
|
||||
logger.e("Error fetching contacts: $e", error: e, stackTrace: st);
|
||||
appLogger.e("Error fetching contacts: $e", error: e, stackTrace: st);
|
||||
showAppSnackbar(
|
||||
title: "Error",
|
||||
message: "Failed to fetch contacts.",
|
||||
|
@ -5,8 +5,7 @@ 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 'package:marco/helpers/services/app_logger.dart';
|
||||
import 'package:marco/helpers/services/api_service.dart';
|
||||
import 'package:marco/helpers/widgets/my_image_compressor.dart';
|
||||
import 'package:marco/model/attendance_model.dart';
|
||||
@ -17,8 +16,6 @@ import 'package:marco/model/regularization_log_model.dart';
|
||||
import 'package:marco/model/attendance_log_view_model.dart';
|
||||
import 'package:marco/controller/project_controller.dart';
|
||||
|
||||
final Logger log = Logger();
|
||||
|
||||
class AttendanceController extends GetxController {
|
||||
// Data lists
|
||||
List<AttendanceModel> attendances = [];
|
||||
@ -61,7 +58,7 @@ class AttendanceController extends GetxController {
|
||||
final today = DateTime.now();
|
||||
startDateAttendance = today.subtract(const Duration(days: 7));
|
||||
endDateAttendance = today.subtract(const Duration(days: 1));
|
||||
log.i("Default date range set: $startDateAttendance to $endDateAttendance");
|
||||
appLogger.i("Default date range set: $startDateAttendance to $endDateAttendance");
|
||||
}
|
||||
|
||||
/// Checks and requests location permission, returns true if granted.
|
||||
@ -71,13 +68,13 @@ class AttendanceController extends GetxController {
|
||||
if (permission == LocationPermission.denied) {
|
||||
permission = await Geolocator.requestPermission();
|
||||
if (permission == LocationPermission.denied) {
|
||||
log.w('Location permissions are denied');
|
||||
appLogger.w('Location permissions are denied');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (permission == LocationPermission.deniedForever) {
|
||||
log.e('Location permissions are permanently denied');
|
||||
appLogger.e('Location permissions are permanently denied');
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -93,9 +90,9 @@ class AttendanceController extends GetxController {
|
||||
|
||||
if (response != null && response.isNotEmpty) {
|
||||
projects = response.map((json) => ProjectModel.fromJson(json)).toList();
|
||||
log.i("Projects fetched: ${projects.length}");
|
||||
appLogger.i("Projects fetched: ${projects.length}");
|
||||
} else {
|
||||
log.e("Failed to fetch projects or no projects available.");
|
||||
appLogger.e("Failed to fetch projects or no projects available.");
|
||||
projects = [];
|
||||
}
|
||||
|
||||
@ -127,7 +124,7 @@ class AttendanceController extends GetxController {
|
||||
|
||||
isLoading.value = false;
|
||||
|
||||
log.i("Project data fetched for project ID: $projectId");
|
||||
appLogger.i("Project data fetched for project ID: $projectId");
|
||||
}
|
||||
|
||||
/// Fetches employees for the given project.
|
||||
@ -146,10 +143,10 @@ class AttendanceController extends GetxController {
|
||||
uploadingStates[emp.id] = false.obs;
|
||||
}
|
||||
|
||||
log.i("Employees fetched: ${employees.length} for project $projectId");
|
||||
appLogger.i("Employees fetched: ${employees.length} for project $projectId");
|
||||
update();
|
||||
} else {
|
||||
log.e("Failed to fetch employees for project $projectId");
|
||||
appLogger.e("Failed to fetch employees for project $projectId");
|
||||
}
|
||||
|
||||
isLoadingEmployees.value = false;
|
||||
@ -176,7 +173,7 @@ class AttendanceController extends GetxController {
|
||||
imageQuality: 80,
|
||||
);
|
||||
if (image == null) {
|
||||
log.w("Image capture cancelled.");
|
||||
appLogger.w("Image capture cancelled.");
|
||||
uploadingStates[employeeId]?.value = false;
|
||||
return false;
|
||||
}
|
||||
@ -184,7 +181,7 @@ class AttendanceController extends GetxController {
|
||||
final compressedBytes =
|
||||
await compressImageToUnder100KB(File(image.path));
|
||||
if (compressedBytes == null) {
|
||||
log.e("Image compression failed.");
|
||||
appLogger.e("Image compression failed.");
|
||||
uploadingStates[employeeId]?.value = false;
|
||||
return false;
|
||||
}
|
||||
@ -221,10 +218,10 @@ class AttendanceController extends GetxController {
|
||||
markTime: markTime,
|
||||
);
|
||||
|
||||
log.i("Attendance uploaded for $employeeId, action: $action");
|
||||
appLogger.i("Attendance uploaded for $employeeId, action: $action");
|
||||
return result;
|
||||
} catch (e, stacktrace) {
|
||||
log.e("Error uploading attendance", error: e, stackTrace: stacktrace);
|
||||
appLogger.e("Error uploading attendance", error: e, stackTrace: stacktrace);
|
||||
return false;
|
||||
} finally {
|
||||
uploadingStates[employeeId]?.value = false;
|
||||
@ -276,7 +273,7 @@ class AttendanceController extends GetxController {
|
||||
startDateAttendance = picked.start;
|
||||
endDateAttendance = picked.end;
|
||||
|
||||
log.i("Date range selected: $startDateAttendance to $endDateAttendance");
|
||||
appLogger.i("Date range selected: $startDateAttendance to $endDateAttendance");
|
||||
|
||||
await controller.fetchAttendanceLogs(
|
||||
Get.find<ProjectController>().selectedProject?.id,
|
||||
@ -306,10 +303,10 @@ class AttendanceController extends GetxController {
|
||||
if (response != null) {
|
||||
attendanceLogs =
|
||||
response.map((json) => AttendanceLogModel.fromJson(json)).toList();
|
||||
log.i("Attendance logs fetched: ${attendanceLogs.length}");
|
||||
appLogger.i("Attendance logs fetched: ${attendanceLogs.length}");
|
||||
update();
|
||||
} else {
|
||||
log.e("Failed to fetch attendance logs for project $projectId");
|
||||
appLogger.e("Failed to fetch attendance logs for project $projectId");
|
||||
}
|
||||
|
||||
isLoadingAttendanceLogs.value = false;
|
||||
@ -341,7 +338,7 @@ class AttendanceController extends GetxController {
|
||||
final sortedMap =
|
||||
Map<String, List<AttendanceLogModel>>.fromEntries(sortedEntries);
|
||||
|
||||
log.i("Logs grouped and sorted by check-in date.");
|
||||
appLogger.i("Logs grouped and sorted by check-in date.");
|
||||
return sortedMap;
|
||||
}
|
||||
|
||||
@ -362,10 +359,10 @@ class AttendanceController extends GetxController {
|
||||
regularizationLogs = response
|
||||
.map((json) => RegularizationLogModel.fromJson(json))
|
||||
.toList();
|
||||
log.i("Regularization logs fetched: ${regularizationLogs.length}");
|
||||
appLogger.i("Regularization logs fetched: ${regularizationLogs.length}");
|
||||
update();
|
||||
} else {
|
||||
log.e("Failed to fetch regularization logs for project $projectId");
|
||||
appLogger.e("Failed to fetch regularization logs for project $projectId");
|
||||
}
|
||||
|
||||
isLoadingRegularizationLogs.value = false;
|
||||
@ -391,10 +388,10 @@ class AttendanceController extends GetxController {
|
||||
return b.activityTime!.compareTo(a.activityTime!);
|
||||
});
|
||||
|
||||
log.i("Attendance log view fetched for ID: $id");
|
||||
appLogger.i("Attendance log view fetched for ID: $id");
|
||||
update();
|
||||
} else {
|
||||
log.e("Failed to fetch attendance log view for ID $id");
|
||||
appLogger.e("Failed to fetch attendance log view for ID $id");
|
||||
}
|
||||
|
||||
isLoadingLogView.value = false;
|
||||
|
@ -1,12 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
import 'package:marco/helpers/services/app_logger.dart';
|
||||
import 'package:marco/helpers/services/api_service.dart';
|
||||
import 'package:marco/model/project_model.dart';
|
||||
import 'package:marco/model/daily_task_model.dart';
|
||||
|
||||
final Logger log = Logger();
|
||||
|
||||
class DailyTaskController extends GetxController {
|
||||
List<ProjectModel> projects = [];
|
||||
String? selectedProjectId;
|
||||
@ -41,7 +39,7 @@ class DailyTaskController extends GetxController {
|
||||
final today = DateTime.now();
|
||||
startDateTask = today.subtract(const Duration(days: 7));
|
||||
endDateTask = today;
|
||||
log.i("Default date range set: $startDateTask to $endDateTask");
|
||||
appLogger.i("Default date range set: $startDateTask to $endDateTask");
|
||||
}
|
||||
|
||||
Future<void> fetchTaskData(String? projectId) async {
|
||||
@ -73,11 +71,11 @@ class DailyTaskController extends GetxController {
|
||||
// Flatten the grouped tasks into the existing dailyTasks list
|
||||
dailyTasks = groupedDailyTasks.values.expand((list) => list).toList();
|
||||
|
||||
log.i("Daily tasks fetched and grouped: ${dailyTasks.length}");
|
||||
appLogger.i("Daily tasks fetched and grouped: ${dailyTasks.length}");
|
||||
|
||||
update();
|
||||
} else {
|
||||
log.e("Failed to fetch daily tasks for project $projectId");
|
||||
appLogger.e("Failed to fetch daily tasks for project $projectId");
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,7 +99,7 @@ class DailyTaskController extends GetxController {
|
||||
startDateTask = picked.start;
|
||||
endDateTask = picked.end;
|
||||
|
||||
log.i("Date range selected: $startDateTask to $endDateTask");
|
||||
appLogger.i("Date range selected: $startDateTask to $endDateTask");
|
||||
|
||||
await controller.fetchTaskData(controller.selectedProjectId);
|
||||
}
|
||||
|
@ -1,10 +1,8 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
import 'package:marco/helpers/services/app_logger.dart';
|
||||
import 'package:marco/helpers/services/api_service.dart';
|
||||
import 'package:marco/controller/project_controller.dart';
|
||||
|
||||
final Logger log = Logger();
|
||||
|
||||
class DashboardController extends GetxController {
|
||||
// Observables
|
||||
final RxList<Map<String, dynamic>> roleWiseData =
|
||||
@ -21,7 +19,7 @@ void onInit() {
|
||||
super.onInit();
|
||||
|
||||
// Log to verify order of controller initialization
|
||||
log.i('DashboardController initialized with project ID: ${projectController.selectedProjectId.value}');
|
||||
appLogger.i('DashboardController initialized with project ID: ${projectController.selectedProjectId.value}');
|
||||
|
||||
if (projectController.selectedProjectId.value.isNotEmpty) {
|
||||
fetchRoleWiseAttendance();
|
||||
@ -30,7 +28,7 @@ void onInit() {
|
||||
// React to project change
|
||||
ever<String>(projectController.selectedProjectId, (id) {
|
||||
if (id.isNotEmpty) {
|
||||
log.i('Project changed to $id, fetching attendance');
|
||||
appLogger.i('Project changed to $id, fetching attendance');
|
||||
fetchRoleWiseAttendance();
|
||||
}
|
||||
});
|
||||
@ -72,7 +70,7 @@ void onInit() {
|
||||
final String projectId = projectController.selectedProjectId.value;
|
||||
|
||||
if (projectId.isEmpty) {
|
||||
log.w('Project ID is empty, skipping API call.');
|
||||
appLogger.w('Project ID is empty, skipping API call.');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -85,13 +83,13 @@ void onInit() {
|
||||
if (response != null) {
|
||||
roleWiseData.value =
|
||||
response.map((e) => Map<String, dynamic>.from(e)).toList();
|
||||
log.i('Attendance overview fetched successfully.');
|
||||
appLogger.i('Attendance overview fetched successfully.');
|
||||
} else {
|
||||
log.e('Failed to fetch attendance overview: response is null.');
|
||||
appLogger.e('Failed to fetch attendance overview: response is null.');
|
||||
roleWiseData.clear();
|
||||
}
|
||||
} catch (e, st) {
|
||||
log.e('Error fetching attendance overview', error: e, stackTrace: st);
|
||||
appLogger.e('Error fetching attendance overview', error: e, stackTrace: st);
|
||||
roleWiseData.clear();
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
import 'package:marco/helpers/services/app_logger.dart';
|
||||
import 'package:marco/helpers/services/api_service.dart';
|
||||
import 'package:marco/model/attendance_model.dart';
|
||||
import 'package:marco/model/project_model.dart';
|
||||
@ -7,7 +7,6 @@ import 'package:marco/model/employee_model.dart';
|
||||
import 'package:marco/model/employees/employee_details_model.dart';
|
||||
import 'package:marco/controller/project_controller.dart';
|
||||
|
||||
final Logger log = Logger();
|
||||
|
||||
class EmployeesScreenController extends GetxController {
|
||||
List<AttendanceModel> attendances = [];
|
||||
@ -45,9 +44,9 @@ class EmployeesScreenController extends GetxController {
|
||||
ApiService.getProjects,
|
||||
onSuccess: (data) {
|
||||
projects = data.map((json) => ProjectModel.fromJson(json)).toList();
|
||||
log.i("Projects fetched: ${projects.length} projects loaded.");
|
||||
appLogger.i("Projects fetched: ${projects.length} projects loaded.");
|
||||
},
|
||||
onEmpty: () => log.w("No project data found or API call failed."),
|
||||
onEmpty: () => appLogger.w("No project data found or API call failed."),
|
||||
);
|
||||
isLoading.value = false;
|
||||
update();
|
||||
@ -55,7 +54,7 @@ class EmployeesScreenController extends GetxController {
|
||||
|
||||
void clearEmployees() {
|
||||
employees.clear(); // Correct way to clear RxList
|
||||
log.i("Employees cleared");
|
||||
appLogger.i("Employees cleared");
|
||||
update(['employee_screen_controller']);
|
||||
}
|
||||
|
||||
@ -65,11 +64,11 @@ class EmployeesScreenController extends GetxController {
|
||||
ApiService.getAllEmployees,
|
||||
onSuccess: (data) {
|
||||
employees.assignAll(data.map((json) => EmployeeModel.fromJson(json)));
|
||||
log.i("All Employees fetched: ${employees.length} employees loaded.");
|
||||
appLogger.i("All Employees fetched: ${employees.length} employees loaded.");
|
||||
},
|
||||
onEmpty: () {
|
||||
employees.clear(); // Always clear on empty
|
||||
log.w("No Employee data found or API call failed.");
|
||||
appLogger.w("No Employee data found or API call failed.");
|
||||
},
|
||||
);
|
||||
isLoading.value = false;
|
||||
@ -78,7 +77,7 @@ class EmployeesScreenController extends GetxController {
|
||||
|
||||
Future<void> fetchEmployeesByProject(String? projectId) async {
|
||||
if (projectId == null || projectId.isEmpty) {
|
||||
log.e("Project ID is required but was null or empty.");
|
||||
appLogger.e("Project ID is required but was null or empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -90,14 +89,14 @@ class EmployeesScreenController extends GetxController {
|
||||
for (var emp in employees) {
|
||||
uploadingStates[emp.id] = false.obs;
|
||||
}
|
||||
log.i("Employees fetched: ${employees.length} for project $projectId");
|
||||
appLogger.i("Employees fetched: ${employees.length} for project $projectId");
|
||||
},
|
||||
onEmpty: () {
|
||||
employees.clear();
|
||||
log.w("No employees found for project $projectId.");
|
||||
appLogger.w("No employees found for project $projectId.");
|
||||
},
|
||||
onError: (e) =>
|
||||
log.e("Error fetching employees for project $projectId: $e"),
|
||||
appLogger.e("Error fetching employees for project $projectId: $e"),
|
||||
);
|
||||
isLoading.value = false;
|
||||
update(['employee_screen_controller']);
|
||||
@ -120,7 +119,7 @@ class EmployeesScreenController extends GetxController {
|
||||
if (onError != null) {
|
||||
onError(e);
|
||||
} else {
|
||||
log.e("API call error: $e");
|
||||
appLogger.e("API call error: $e");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -163,7 +162,7 @@ class EmployeesScreenController extends GetxController {
|
||||
if (onError != null) {
|
||||
onError(e);
|
||||
} else {
|
||||
log.e("API call error: $e");
|
||||
appLogger.e("API call error: $e");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
import 'package:marco/helpers/services/app_logger.dart';
|
||||
import 'package:marco/helpers/services/api_service.dart';
|
||||
import 'package:marco/helpers/theme/theme_customizer.dart';
|
||||
import 'package:marco/model/project_model.dart';
|
||||
|
||||
|
||||
final Logger log = Logger();
|
||||
|
||||
class LayoutController extends GetxController {
|
||||
// Theme Customization
|
||||
@ -63,9 +62,9 @@ class LayoutController extends GetxController {
|
||||
final fetchedProjects = response.map((json) => ProjectModel.fromJson(json)).toList();
|
||||
projects.assignAll(fetchedProjects);
|
||||
selectedProjectId = RxString(fetchedProjects.first.id.toString());
|
||||
log.i("Projects fetched: ${fetchedProjects.length}");
|
||||
appLogger.i("Projects fetched: ${fetchedProjects.length}");
|
||||
} else {
|
||||
log.w("No projects found or API call failed.");
|
||||
appLogger.w("No projects found or API call failed.");
|
||||
}
|
||||
|
||||
isLoadingProjects.value = false;
|
||||
|
@ -2,14 +2,14 @@ import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
import 'package:marco/helpers/services/app_logger.dart';
|
||||
|
||||
import 'package:marco/helpers/services/permission_service.dart';
|
||||
import 'package:marco/model/user_permission.dart';
|
||||
import 'package:marco/model/employee_info.dart';
|
||||
import 'package:marco/model/projects_model.dart';
|
||||
|
||||
final log = Logger();
|
||||
|
||||
|
||||
class PermissionController extends GetxController {
|
||||
var permissions = <UserPermission>[].obs;
|
||||
@ -47,9 +47,9 @@ class PermissionController extends GetxController {
|
||||
);
|
||||
}
|
||||
|
||||
log.i("User data successfully stored in SharedPreferences.");
|
||||
appLogger.i("User data successfully stored in SharedPreferences.");
|
||||
} catch (e, stacktrace) {
|
||||
log.e("Error storing data", error: e, stackTrace: stacktrace);
|
||||
appLogger.e("Error storing data", error: e, stackTrace: stacktrace);
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,7 +58,7 @@ class PermissionController extends GetxController {
|
||||
if (token?.isNotEmpty ?? false) {
|
||||
await loadData(token!);
|
||||
} else {
|
||||
log.w("No token found for loading API data.");
|
||||
appLogger.w("No token found for loading API data.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,9 +67,9 @@ class PermissionController extends GetxController {
|
||||
final userData = await PermissionService.fetchAllUserData(token);
|
||||
_updateState(userData);
|
||||
await _storeData();
|
||||
log.i("Data loaded and state updated successfully.");
|
||||
appLogger.i("Data loaded and state updated successfully.");
|
||||
} catch (e, stacktrace) {
|
||||
log.e("Error loading data from API", error: e, stackTrace: stacktrace);
|
||||
appLogger.e("Error loading data from API", error: e, stackTrace: stacktrace);
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,9 +78,9 @@ class PermissionController extends GetxController {
|
||||
permissions.assignAll(userData['permissions']);
|
||||
employeeInfo.value = userData['employeeInfo'];
|
||||
projectsInfo.assignAll(userData['projects']);
|
||||
log.i("State updated with new user data.");
|
||||
appLogger.i("State updated with new user data.");
|
||||
} catch (e, stacktrace) {
|
||||
log.e("Error updating state", error: e, stackTrace: stacktrace);
|
||||
appLogger.e("Error updating state", error: e, stackTrace: stacktrace);
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,34 +89,34 @@ class PermissionController extends GetxController {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
return prefs.getString('jwt_token');
|
||||
} catch (e, stacktrace) {
|
||||
log.e("Error retrieving auth token", error: e, stackTrace: stacktrace);
|
||||
appLogger.e("Error retrieving auth token", error: e, stackTrace: stacktrace);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
void _startAutoRefresh() {
|
||||
_refreshTimer = Timer.periodic(Duration(minutes: 30), (timer) async {
|
||||
log.i("Auto-refresh triggered.");
|
||||
appLogger.i("Auto-refresh triggered.");
|
||||
await _loadDataFromAPI();
|
||||
});
|
||||
}
|
||||
|
||||
bool hasPermission(String permissionId) {
|
||||
final hasPerm = permissions.any((p) => p.id == permissionId);
|
||||
log.d("Checking permission $permissionId: $hasPerm");
|
||||
appLogger.d("Checking permission $permissionId: $hasPerm");
|
||||
return hasPerm;
|
||||
}
|
||||
|
||||
bool isUserAssignedToProject(String projectId) {
|
||||
final assigned = projectsInfo.any((project) => project.id == projectId);
|
||||
log.d("Checking project assignment for $projectId: $assigned");
|
||||
appLogger.d("Checking project assignment for $projectId: $assigned");
|
||||
return assigned;
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
_refreshTimer?.cancel();
|
||||
log.i("PermissionController disposed and timer cancelled.");
|
||||
appLogger.i("PermissionController disposed and timer cancelled.");
|
||||
super.onClose();
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,9 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
import 'package:marco/helpers/services/app_logger.dart';
|
||||
import 'package:marco/helpers/services/api_service.dart';
|
||||
import 'package:marco/model/global_project_model.dart';
|
||||
import 'package:marco/helpers/services/storage/local_storage.dart';
|
||||
|
||||
final Logger log = Logger();
|
||||
|
||||
class ProjectController extends GetxController {
|
||||
RxList<GlobalProjectModel> projects = <GlobalProjectModel>[].obs;
|
||||
RxString selectedProjectId = ''.obs;
|
||||
@ -62,9 +60,9 @@ class ProjectController extends GetxController {
|
||||
}
|
||||
|
||||
isProjectSelectionExpanded.value = false;
|
||||
log.i("Projects fetched: ${projects.length}");
|
||||
appLogger.i("Projects fetched: ${projects.length}");
|
||||
} else {
|
||||
log.w("No projects found or API call failed.");
|
||||
appLogger.w("No projects found or API call failed.");
|
||||
}
|
||||
|
||||
isLoadingProjects.value = false;
|
||||
|
@ -1,11 +1,10 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
import 'package:marco/helpers/services/app_logger.dart';
|
||||
import 'package:marco/helpers/services/api_service.dart';
|
||||
import 'package:marco/helpers/widgets/my_form_validator.dart';
|
||||
import 'package:marco/helpers/widgets/my_snackbar.dart';
|
||||
import 'package:marco/model/dailyTaskPlaning/master_work_category_model.dart';
|
||||
|
||||
final Logger log = Logger();
|
||||
|
||||
class AddTaskController extends GetxController {
|
||||
RxMap<String, RxBool> uploadingStates = <String, RxBool>{}.obs;
|
||||
@ -50,7 +49,7 @@ class AddTaskController extends GetxController {
|
||||
required List<String> taskTeam,
|
||||
DateTime? assignmentDate,
|
||||
}) async {
|
||||
logger.i("Starting assign task...");
|
||||
appLogger.i("Starting assign task...");
|
||||
|
||||
final response = await ApiService.assignDailyTask(
|
||||
workItemId: workItemId,
|
||||
@ -61,7 +60,7 @@ class AddTaskController extends GetxController {
|
||||
);
|
||||
|
||||
if (response == true) {
|
||||
logger.i("Task assigned successfully.");
|
||||
appLogger.i("Task assigned successfully.");
|
||||
showAppSnackbar(
|
||||
title: "Success",
|
||||
message: "Task assigned successfully!",
|
||||
@ -69,7 +68,7 @@ class AddTaskController extends GetxController {
|
||||
);
|
||||
return true;
|
||||
} else {
|
||||
logger.e("Failed to assign task.");
|
||||
appLogger.e("Failed to assign task.");
|
||||
showAppSnackbar(
|
||||
title: "Error",
|
||||
message: "Failed to assign task.",
|
||||
@ -88,7 +87,7 @@ class AddTaskController extends GetxController {
|
||||
required String categoryId,
|
||||
DateTime? assignmentDate,
|
||||
}) async {
|
||||
logger.i("Creating new task...");
|
||||
appLogger.i("Creating new task...");
|
||||
|
||||
final response = await ApiService.createTask(
|
||||
parentTaskId: parentTaskId,
|
||||
@ -102,7 +101,7 @@ class AddTaskController extends GetxController {
|
||||
);
|
||||
|
||||
if (response == true) {
|
||||
logger.i("Task created successfully.");
|
||||
appLogger.i("Task created successfully.");
|
||||
showAppSnackbar(
|
||||
title: "Success",
|
||||
message: "Task created successfully!",
|
||||
@ -110,7 +109,7 @@ class AddTaskController extends GetxController {
|
||||
);
|
||||
return true;
|
||||
} else {
|
||||
logger.e("Failed to create task.");
|
||||
appLogger.e("Failed to create task.");
|
||||
showAppSnackbar(
|
||||
title: "Error",
|
||||
message: "Failed to create task.",
|
||||
@ -138,14 +137,14 @@ class AddTaskController extends GetxController {
|
||||
};
|
||||
categoryIdNameMap.assignAll(mapped);
|
||||
|
||||
logger.i("Work categories fetched: ${dataList.length}");
|
||||
appLogger.i("Work categories fetched: ${dataList.length}");
|
||||
} catch (e) {
|
||||
logger.e("Error parsing work categories: $e");
|
||||
appLogger.e("Error parsing work categories: $e");
|
||||
workMasterCategories.clear();
|
||||
categoryIdNameMap.clear();
|
||||
}
|
||||
} else {
|
||||
logger.w("No work categories found or API call failed.");
|
||||
appLogger.w("No work categories found or API call failed.");
|
||||
}
|
||||
|
||||
isLoadingWorkMasterCategories.value = false;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
import 'package:marco/helpers/services/app_logger.dart';
|
||||
import 'package:marco/helpers/services/api_service.dart';
|
||||
import 'package:marco/model/project_model.dart';
|
||||
import 'package:marco/model/dailyTaskPlaning/daily_task_planing_model.dart';
|
||||
@ -7,7 +7,6 @@ import 'package:marco/model/employee_model.dart';
|
||||
import 'package:marco/helpers/widgets/my_form_validator.dart';
|
||||
import 'package:marco/helpers/widgets/my_snackbar.dart';
|
||||
|
||||
final Logger log = Logger();
|
||||
|
||||
class DailyTaskPlaningController extends GetxController {
|
||||
List<ProjectModel> projects = [];
|
||||
@ -56,20 +55,20 @@ class DailyTaskPlaningController extends GetxController {
|
||||
}
|
||||
|
||||
Future<void> fetchRoles() async {
|
||||
logger.i("Fetching roles...");
|
||||
appLogger.i("Fetching roles...");
|
||||
final result = await ApiService.getRoles();
|
||||
if (result != null) {
|
||||
roles = List<Map<String, dynamic>>.from(result);
|
||||
logger.i("Roles fetched successfully.");
|
||||
appLogger.i("Roles fetched successfully.");
|
||||
update();
|
||||
} else {
|
||||
logger.e("Failed to fetch roles.");
|
||||
appLogger.e("Failed to fetch roles.");
|
||||
}
|
||||
}
|
||||
|
||||
void onRoleSelected(String? roleId) {
|
||||
selectedRoleId.value = roleId;
|
||||
logger.i("Role selected: $roleId");
|
||||
appLogger.i("Role selected: $roleId");
|
||||
}
|
||||
|
||||
Future<bool> assignDailyTask({
|
||||
@ -79,7 +78,7 @@ class DailyTaskPlaningController extends GetxController {
|
||||
required List<String> taskTeam,
|
||||
DateTime? assignmentDate,
|
||||
}) async {
|
||||
logger.i("Starting assign task...");
|
||||
appLogger.i("Starting assign task...");
|
||||
|
||||
final response = await ApiService.assignDailyTask(
|
||||
workItemId: workItemId,
|
||||
@ -90,7 +89,7 @@ class DailyTaskPlaningController extends GetxController {
|
||||
);
|
||||
|
||||
if (response == true) {
|
||||
logger.i("Task assigned successfully.");
|
||||
appLogger.i("Task assigned successfully.");
|
||||
showAppSnackbar(
|
||||
title: "Success",
|
||||
message: "Task assigned successfully!",
|
||||
@ -98,7 +97,7 @@ class DailyTaskPlaningController extends GetxController {
|
||||
);
|
||||
return true;
|
||||
} else {
|
||||
logger.e("Failed to assign task.");
|
||||
appLogger.e("Failed to assign task.");
|
||||
showAppSnackbar(
|
||||
title: "Error",
|
||||
message: "Failed to assign task.",
|
||||
@ -115,15 +114,15 @@ class DailyTaskPlaningController extends GetxController {
|
||||
|
||||
final response = await ApiService.getProjects();
|
||||
if (response?.isEmpty ?? true) {
|
||||
log.w("No project data found or API call failed.");
|
||||
appLogger.w("No project data found or API call failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
projects = response!.map((json) => ProjectModel.fromJson(json)).toList();
|
||||
log.i("Projects fetched: ${projects.length} projects loaded.");
|
||||
appLogger.i("Projects fetched: ${projects.length} projects loaded.");
|
||||
update();
|
||||
} catch (e, stack) {
|
||||
log.e("Error fetching projects", error: e, stackTrace: stack);
|
||||
appLogger.e("Error fetching projects", error: e, stackTrace: stack);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
@ -140,16 +139,16 @@ class DailyTaskPlaningController extends GetxController {
|
||||
final data = response['data'];
|
||||
if (data != null) {
|
||||
dailyTasks = [TaskPlanningDetailsModel.fromJson(data)];
|
||||
log.i("Daily task Planning Details fetched.");
|
||||
appLogger.i("Daily task Planning Details fetched.");
|
||||
} else {
|
||||
log.e("Data field is null");
|
||||
appLogger.e("Data field is null");
|
||||
}
|
||||
} else {
|
||||
log.e(
|
||||
appLogger.e(
|
||||
"Failed to fetch daily task planning Details for project $projectId");
|
||||
}
|
||||
} catch (e, stack) {
|
||||
log.e("Error fetching daily task data", error: e, stackTrace: stack);
|
||||
appLogger.e("Error fetching daily task data", error: e, stackTrace: stack);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
update();
|
||||
@ -158,7 +157,7 @@ class DailyTaskPlaningController extends GetxController {
|
||||
|
||||
Future<void> fetchEmployeesByProject(String? projectId) async {
|
||||
if (projectId == null || projectId.isEmpty) {
|
||||
log.e("Project ID is required but was null or empty.");
|
||||
appLogger.e("Project ID is required but was null or empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -171,13 +170,13 @@ class DailyTaskPlaningController extends GetxController {
|
||||
for (var emp in employees) {
|
||||
uploadingStates[emp.id] = false.obs;
|
||||
}
|
||||
log.i("Employees fetched: ${employees.length} for project $projectId");
|
||||
appLogger.i("Employees fetched: ${employees.length} for project $projectId");
|
||||
} else {
|
||||
log.w("No employees found for project $projectId.");
|
||||
appLogger.w("No employees found for project $projectId.");
|
||||
employees = [];
|
||||
}
|
||||
} catch (e) {
|
||||
log.e("Error fetching employees for project $projectId: $e");
|
||||
appLogger.e("Error fetching employees for project $projectId: $e");
|
||||
}
|
||||
|
||||
update();
|
||||
|
@ -4,7 +4,7 @@ import 'dart:io';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
import 'package:marco/helpers/services/app_logger.dart';
|
||||
|
||||
import 'package:marco/controller/my_controller.dart';
|
||||
import 'package:marco/controller/task_planing/daily_task_planing_controller.dart';
|
||||
@ -14,7 +14,6 @@ import 'package:marco/helpers/widgets/my_image_compressor.dart';
|
||||
import 'package:marco/helpers/widgets/my_snackbar.dart';
|
||||
import 'package:marco/model/dailyTaskPlaning/work_status_model.dart';
|
||||
|
||||
final Logger logger = Logger();
|
||||
|
||||
enum ApiStatus { idle, loading, success, failure }
|
||||
|
||||
@ -79,7 +78,7 @@ class ReportTaskActionController extends MyController {
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
logger.i("Initializing ReportTaskController...");
|
||||
appLogger.i("Initializing ReportTaskController...");
|
||||
_initializeFormFields();
|
||||
}
|
||||
|
||||
@ -120,11 +119,11 @@ class ReportTaskActionController extends MyController {
|
||||
required String approvedTaskCount,
|
||||
List<File>? images,
|
||||
}) async {
|
||||
logger.i("Starting task approval...");
|
||||
logger.i("Project ID: $projectId");
|
||||
logger.i("Comment: $comment");
|
||||
logger.i("Report Action ID: $reportActionId");
|
||||
logger.i("Approved Task Count: $approvedTaskCount");
|
||||
appLogger.i("Starting task approval...");
|
||||
appLogger.i("Project ID: $projectId");
|
||||
appLogger.i("Comment: $comment");
|
||||
appLogger.i("Report Action ID: $reportActionId");
|
||||
appLogger.i("Approved Task Count: $approvedTaskCount");
|
||||
|
||||
if (projectId.isEmpty || reportActionId.isEmpty) {
|
||||
_showError("Project ID and Report Action ID are required.");
|
||||
@ -172,7 +171,7 @@ class ReportTaskActionController extends MyController {
|
||||
return false;
|
||||
}
|
||||
} catch (e) {
|
||||
logger.e("Error approving task: $e");
|
||||
appLogger.e("Error approving task: $e");
|
||||
_showError("An error occurred.");
|
||||
return false;
|
||||
} finally {
|
||||
@ -191,7 +190,7 @@ class ReportTaskActionController extends MyController {
|
||||
required String comment,
|
||||
List<File>? images,
|
||||
}) async {
|
||||
logger.i("Starting task comment...");
|
||||
appLogger.i("Starting task comment...");
|
||||
|
||||
if (commentController.text.trim().isEmpty) {
|
||||
_showError("Comment is required.");
|
||||
@ -218,7 +217,7 @@ class ReportTaskActionController extends MyController {
|
||||
_showError("Failed to comment task.");
|
||||
}
|
||||
} catch (e) {
|
||||
logger.e("Error commenting task: $e");
|
||||
appLogger.e("Error commenting task: $e");
|
||||
_showError("An error occurred while commenting the task.");
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
@ -236,7 +235,7 @@ class ReportTaskActionController extends MyController {
|
||||
final model = WorkStatusResponseModel.fromJson(response);
|
||||
workStatus.assignAll(model.data);
|
||||
} else {
|
||||
logger.w("No work statuses found or API call failed.");
|
||||
appLogger.w("No work statuses found or API call failed.");
|
||||
}
|
||||
|
||||
isLoadingWorkStatus.value = false;
|
||||
|
@ -4,7 +4,7 @@ import 'package:marco/controller/my_controller.dart';
|
||||
import 'package:marco/helpers/widgets/my_form_validator.dart';
|
||||
import 'package:marco/helpers/services/api_service.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
import 'package:marco/helpers/services/app_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';
|
||||
@ -12,7 +12,6 @@ import 'dart:io';
|
||||
import 'dart:convert';
|
||||
import 'package:marco/helpers/widgets/my_image_compressor.dart';
|
||||
|
||||
final Logger logger = Logger();
|
||||
|
||||
enum ApiStatus { idle, loading, success, failure }
|
||||
|
||||
@ -45,7 +44,7 @@ class ReportTaskController extends MyController {
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
logger.i("Initializing ReportTaskController...");
|
||||
appLogger.i("Initializing ReportTaskController...");
|
||||
|
||||
basicValidator.addField('assigned_date',
|
||||
label: "Assigned Date", controller: assignedDateController);
|
||||
@ -72,7 +71,7 @@ class ReportTaskController extends MyController {
|
||||
basicValidator.addField('planned_work',
|
||||
label: "Planned Work", controller: plannedWorkController);
|
||||
|
||||
logger.i(
|
||||
appLogger.i(
|
||||
"Fields initialized for assigned_date, work_area, activity, team_size, assigned, completed_work, and comment.");
|
||||
}
|
||||
|
||||
@ -100,7 +99,7 @@ class ReportTaskController extends MyController {
|
||||
required DateTime reportedDate,
|
||||
List<File>? images,
|
||||
}) async {
|
||||
logger.i("Starting task report...");
|
||||
appLogger.i("Starting task report...");
|
||||
|
||||
final completedWork = completedWorkController.text.trim();
|
||||
|
||||
@ -187,7 +186,7 @@ class ReportTaskController extends MyController {
|
||||
return false;
|
||||
}
|
||||
} catch (e) {
|
||||
logger.e("Error reporting task: $e");
|
||||
appLogger.e("Error reporting task: $e");
|
||||
reportStatus.value = ApiStatus.failure;
|
||||
showAppSnackbar(
|
||||
title: "Error",
|
||||
@ -225,7 +224,7 @@ class ReportTaskController extends MyController {
|
||||
required String comment,
|
||||
List<File>? images,
|
||||
}) async {
|
||||
logger.i("Starting task comment...");
|
||||
appLogger.i("Starting task comment...");
|
||||
|
||||
final commentField = commentController.text.trim();
|
||||
if (commentField.isEmpty) {
|
||||
@ -268,7 +267,7 @@ class ReportTaskController extends MyController {
|
||||
comment: commentField,
|
||||
images: imageData,
|
||||
).timeout(const Duration(seconds: 30), onTimeout: () {
|
||||
logger.e("Request timed out.");
|
||||
appLogger.e("Request timed out.");
|
||||
throw Exception("Request timed out.");
|
||||
});
|
||||
|
||||
@ -287,7 +286,7 @@ class ReportTaskController extends MyController {
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
logger.e("Error commenting task: $e");
|
||||
appLogger.e("Error commenting task: $e");
|
||||
showAppSnackbar(
|
||||
title: "Error",
|
||||
message: "An error occurred while commenting the task.",
|
||||
|
@ -3,13 +3,13 @@ import 'package:get/get.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
|
||||
import 'package:marco/helpers/services/auth_service.dart';
|
||||
import 'package:marco/helpers/services/api_endpoints.dart';
|
||||
import 'package:marco/helpers/services/storage/local_storage.dart';
|
||||
import 'package:jwt_decoder/jwt_decoder.dart';
|
||||
final Logger logger = Logger();
|
||||
|
||||
import 'package:marco/helpers/services/app_logger.dart';
|
||||
class ApiService {
|
||||
static const Duration timeout = Duration(seconds: 30);
|
||||
static const bool enableLogs = true;
|
||||
@ -21,7 +21,7 @@ class ApiService {
|
||||
final token = await LocalStorage.getJwtToken();
|
||||
|
||||
if (token == null) {
|
||||
if (enableLogs) logger.w("No JWT token found.");
|
||||
if (enableLogs) appLogger.w("No JWT token found.");
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -65,7 +65,7 @@ class ApiService {
|
||||
};
|
||||
|
||||
static void _log(String message) {
|
||||
if (enableLogs) logger.i(message);
|
||||
if (enableLogs) appLogger.i(message);
|
||||
}
|
||||
|
||||
static dynamic _parseResponse(http.Response response, {String label = ''}) {
|
||||
|
@ -6,9 +6,9 @@ import 'package:marco/helpers/services/storage/local_storage.dart';
|
||||
import 'package:marco/helpers/theme/theme_customizer.dart';
|
||||
import 'package:marco/helpers/theme/app_theme.dart';
|
||||
import 'package:url_strategy/url_strategy.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
import 'package:marco/helpers/services/app_logger.dart';
|
||||
|
||||
|
||||
final Logger logger = Logger();
|
||||
|
||||
Future<void> initializeApp() async {
|
||||
setPathUrlStrategy();
|
||||
@ -24,5 +24,5 @@ Future<void> initializeApp() async {
|
||||
Get.put(ProjectController(), permanent: true);
|
||||
AppStyle.init();
|
||||
|
||||
logger.i("App initialization completed successfully.");
|
||||
appLogger.i("App initialization completed successfully.");
|
||||
}
|
||||
|
107
lib/helpers/services/app_logger.dart
Normal file
107
lib/helpers/services/app_logger.dart
Normal file
@ -0,0 +1,107 @@
|
||||
import 'dart:io';
|
||||
import 'package:logger/logger.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
|
||||
/// Global logger instance
|
||||
late final Logger appLogger;
|
||||
|
||||
/// Log file output handler
|
||||
late final FileLogOutput fileLogOutput;
|
||||
|
||||
/// Initialize logging (call once in `main()`)
|
||||
Future<void> initLogging() async {
|
||||
await requestStoragePermission();
|
||||
fileLogOutput = FileLogOutput();
|
||||
appLogger = Logger(
|
||||
printer: SimpleFileLogPrinter(),
|
||||
output: fileLogOutput,
|
||||
);
|
||||
}
|
||||
|
||||
/// Request storage permission (for Android 11+)
|
||||
Future<void> requestStoragePermission() async {
|
||||
final status = await Permission.manageExternalStorage.status;
|
||||
if (!status.isGranted) {
|
||||
await Permission.manageExternalStorage.request();
|
||||
}
|
||||
}
|
||||
|
||||
/// Custom log output that writes to a local `.txt` file
|
||||
class FileLogOutput extends LogOutput {
|
||||
File? _logFile;
|
||||
|
||||
/// Initialize log file in Downloads/marco_logs/log_YYYY-MM-DD.txt
|
||||
Future<void> _init() async {
|
||||
if (_logFile != null) return;
|
||||
|
||||
final directory = Directory('/storage/emulated/0/Download/marco_logs');
|
||||
if (!await directory.exists()) {
|
||||
await directory.create(recursive: true);
|
||||
}
|
||||
|
||||
final date = DateFormat('yyyy-MM-dd').format(DateTime.now());
|
||||
final filePath = '${directory.path}/log_$date.txt';
|
||||
_logFile = File(filePath);
|
||||
|
||||
if (!await _logFile!.exists()) {
|
||||
await _logFile!.create();
|
||||
}
|
||||
|
||||
await _cleanOldLogs(directory);
|
||||
}
|
||||
|
||||
@override
|
||||
void output(OutputEvent event) async {
|
||||
await _init();
|
||||
final logMessage = event.lines.join('\n') + '\n';
|
||||
await _logFile!.writeAsString(
|
||||
logMessage,
|
||||
mode: FileMode.append,
|
||||
flush: true,
|
||||
);
|
||||
}
|
||||
|
||||
Future<String> getLogFilePath() async {
|
||||
await _init();
|
||||
return _logFile!.path;
|
||||
}
|
||||
|
||||
Future<void> clearLogs() async {
|
||||
await _init();
|
||||
await _logFile!.writeAsString('');
|
||||
}
|
||||
|
||||
Future<String> readLogs() async {
|
||||
await _init();
|
||||
return _logFile!.readAsString();
|
||||
}
|
||||
|
||||
/// Delete logs older than 3 days
|
||||
Future<void> _cleanOldLogs(Directory directory) async {
|
||||
final files = directory.listSync();
|
||||
final now = DateTime.now();
|
||||
|
||||
for (var file in files) {
|
||||
if (file is File && file.path.endsWith('.txt')) {
|
||||
final stat = await file.stat();
|
||||
if (now.difference(stat.modified).inDays > 3) {
|
||||
await file.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A simple, readable log printer for file output
|
||||
class SimpleFileLogPrinter extends LogPrinter {
|
||||
@override
|
||||
List<String> log(LogEvent event) {
|
||||
final timestamp = DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now());
|
||||
final level = event.level.name.toUpperCase();
|
||||
final message = event.message;
|
||||
final error = event.error != null ? ' | ERROR: ${event.error}' : '';
|
||||
final stack = event.stackTrace != null ? '\nSTACKTRACE:\n${event.stackTrace}' : '';
|
||||
return ['[$timestamp] [$level] $message$error$stack'];
|
||||
}
|
||||
}
|
@ -1,13 +1,12 @@
|
||||
import 'dart:convert';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:logger/logger.dart';
|
||||
|
||||
import 'package:marco/controller/permission_controller.dart';
|
||||
import 'package:marco/controller/project_controller.dart';
|
||||
import 'package:marco/helpers/services/api_endpoints.dart';
|
||||
import 'package:marco/helpers/services/storage/local_storage.dart';
|
||||
|
||||
final Logger logger = Logger();
|
||||
import 'package:marco/helpers/services/app_logger.dart';
|
||||
|
||||
class AuthService {
|
||||
static const String _baseUrl = ApiEndpoints.baseUrl;
|
||||
@ -36,7 +35,7 @@ class AuthService {
|
||||
return {"error": responseData['message'] ?? "Unexpected error occurred"};
|
||||
}
|
||||
} catch (e) {
|
||||
logger.e("Login error: $e");
|
||||
appLogger.e("Login error: $e");
|
||||
return {"error": "Network error. Please check your connection."};
|
||||
}
|
||||
}
|
||||
@ -47,7 +46,7 @@ class AuthService {
|
||||
final refreshToken = await LocalStorage.getRefreshToken();
|
||||
|
||||
if (accessToken == null || refreshToken == null || accessToken.isEmpty || refreshToken.isEmpty) {
|
||||
logger.w("Missing access/refresh token.");
|
||||
appLogger.w("Missing access/refresh token.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -68,14 +67,14 @@ class AuthService {
|
||||
await LocalStorage.setJwtToken(data['data']['token']);
|
||||
await LocalStorage.setRefreshToken(data['data']['refreshToken']);
|
||||
await LocalStorage.setLoggedInUser(true);
|
||||
logger.i("Token refreshed.");
|
||||
appLogger.i("Token refreshed.");
|
||||
return true;
|
||||
} else {
|
||||
logger.w("Refresh token failed: ${data['message']}");
|
||||
appLogger.w("Refresh token failed: ${data['message']}");
|
||||
return false;
|
||||
}
|
||||
} catch (e) {
|
||||
logger.e("Token refresh error: $e");
|
||||
appLogger.e("Token refresh error: $e");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -93,7 +92,7 @@ class AuthService {
|
||||
if (response.statusCode == 200 && data['success'] == true) return null;
|
||||
return {"error": data['message'] ?? "Failed to send reset link."};
|
||||
} catch (e) {
|
||||
logger.e("Forgot password error: $e");
|
||||
appLogger.e("Forgot password error: $e");
|
||||
return {"error": "Network error. Please check your connection."};
|
||||
}
|
||||
}
|
||||
@ -111,7 +110,7 @@ class AuthService {
|
||||
if (response.statusCode == 200 && data['success'] == true) return null;
|
||||
return {"error": data['message'] ?? "Failed to submit demo request."};
|
||||
} catch (e) {
|
||||
logger.e("Request demo error: $e");
|
||||
appLogger.e("Request demo error: $e");
|
||||
return {"error": "Network error. Please check your connection."};
|
||||
}
|
||||
}
|
||||
@ -130,7 +129,7 @@ class AuthService {
|
||||
}
|
||||
return null;
|
||||
} catch (e) {
|
||||
logger.e("Get industries error: $e");
|
||||
appLogger.e("Get industries error: $e");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -156,7 +155,7 @@ class AuthService {
|
||||
if (response.statusCode == 200 && data['success'] == true) return null;
|
||||
return {"error": data['message'] ?? "Failed to generate MPIN."};
|
||||
} catch (e) {
|
||||
logger.e("Generate MPIN error: $e");
|
||||
appLogger.e("Generate MPIN error: $e");
|
||||
return {"error": "Network error. Please check your connection."};
|
||||
}
|
||||
}
|
||||
@ -189,7 +188,7 @@ class AuthService {
|
||||
if (response.statusCode == 200 && data['success'] == true) return null;
|
||||
return {"error": data['message'] ?? "MPIN verification failed."};
|
||||
} catch (e) {
|
||||
logger.e("Verify MPIN error: $e");
|
||||
appLogger.e("Verify MPIN error: $e");
|
||||
return {"error": "Network error. Please check your connection."};
|
||||
}
|
||||
}
|
||||
@ -207,7 +206,7 @@ class AuthService {
|
||||
if (response.statusCode == 200 && data['success'] == true) return null;
|
||||
return {"error": data['message'] ?? "Failed to generate OTP."};
|
||||
} catch (e) {
|
||||
logger.e("Generate OTP error: $e");
|
||||
appLogger.e("Generate OTP error: $e");
|
||||
return {"error": "Network error. Please check your connection."};
|
||||
}
|
||||
}
|
||||
@ -231,7 +230,7 @@ class AuthService {
|
||||
}
|
||||
return {"error": data['message'] ?? "OTP verification failed."};
|
||||
} catch (e) {
|
||||
logger.e("Verify OTP error: $e");
|
||||
appLogger.e("Verify OTP error: $e");
|
||||
return {"error": "Network error. Please check your connection."};
|
||||
}
|
||||
}
|
||||
@ -260,6 +259,6 @@ class AuthService {
|
||||
await Get.find<ProjectController>().fetchProjects();
|
||||
|
||||
isLoggedIn = true;
|
||||
logger.i("Login success initialized.");
|
||||
appLogger.i("Login success initialized.");
|
||||
}
|
||||
}
|
||||
|
79
lib/helpers/services/log_output.dart
Normal file
79
lib/helpers/services/log_output.dart
Normal file
@ -0,0 +1,79 @@
|
||||
import 'dart:io';
|
||||
import 'package:logger/logger.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class FileLogOutput extends LogOutput {
|
||||
late final Directory _logDirectory;
|
||||
late final String _todayLogFileName;
|
||||
|
||||
FileLogOutput() {
|
||||
_init();
|
||||
}
|
||||
|
||||
Future<void> _init() async {
|
||||
_logDirectory = await getApplicationDocumentsDirectory();
|
||||
final today = DateFormat('yyyy-MM-dd').format(DateTime.now());
|
||||
_todayLogFileName = 'log_$today.txt';
|
||||
await _cleanupOldLogs();
|
||||
}
|
||||
|
||||
@override
|
||||
void output(OutputEvent event) async {
|
||||
final file = await _getTodayLogFile();
|
||||
final logMessage = event.lines.join('\n') + '\n';
|
||||
await file.writeAsString(logMessage, mode: FileMode.append, flush: true);
|
||||
}
|
||||
|
||||
Future<File> _getTodayLogFile() async {
|
||||
final path = '${_logDirectory.path}/$_todayLogFileName';
|
||||
final file = File(path);
|
||||
if (!await file.exists()) {
|
||||
await file.create(recursive: true);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
/// Keep only the most recent 3 days of logs
|
||||
Future<void> _cleanupOldLogs() async {
|
||||
final files = _logDirectory
|
||||
.listSync()
|
||||
.whereType<File>()
|
||||
.where((f) => f.path.contains(RegExp(r'log_\d{4}-\d{2}-\d{2}\.txt')))
|
||||
.toList();
|
||||
|
||||
files.sort((a, b) => b.path.compareTo(a.path));
|
||||
|
||||
if (files.length > 3) {
|
||||
final oldFiles = files.sublist(3);
|
||||
for (final f in oldFiles) {
|
||||
try {
|
||||
await f.delete();
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// For reading today's log
|
||||
Future<String> readTodayLogs() async {
|
||||
final file = await _getTodayLogFile();
|
||||
return file.readAsString();
|
||||
}
|
||||
|
||||
/// Read all log files (optional utility)
|
||||
Future<Map<String, String>> readAllLogs() async {
|
||||
final files = _logDirectory
|
||||
.listSync()
|
||||
.whereType<File>()
|
||||
.where((f) => f.path.contains('log_'))
|
||||
.toList();
|
||||
|
||||
Map<String, String> logs = {};
|
||||
for (final f in files) {
|
||||
logs[f.path.split('/').last] = await f.readAsString();
|
||||
}
|
||||
return logs;
|
||||
}
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
import 'dart:convert';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:logger/logger.dart';
|
||||
|
||||
import 'package:marco/helpers/services/app_logger.dart';
|
||||
import 'package:marco/model/user_permission.dart';
|
||||
import 'package:marco/model/employee_info.dart';
|
||||
import 'package:marco/model/projects_model.dart';
|
||||
@ -10,7 +10,7 @@ import 'package:marco/helpers/services/storage/local_storage.dart';
|
||||
import 'package:marco/helpers/services/auth_service.dart';
|
||||
import 'package:marco/helpers/services/api_endpoints.dart';
|
||||
|
||||
final Logger logger = Logger();
|
||||
|
||||
|
||||
class PermissionService {
|
||||
static final Map<String, Map<String, dynamic>> _userDataCache = {};
|
||||
@ -61,7 +61,7 @@ static const String _baseUrl = ApiEndpoints.baseUrl;
|
||||
final error = json.decode(response.body)['message'] ?? 'Unknown error';
|
||||
throw Exception('Failed to fetch user data: $error');
|
||||
} catch (e) {
|
||||
logger.e('Error fetching user data: $e');
|
||||
appLogger.e('Error fetching user data: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
@ -3,9 +3,9 @@ import 'dart:typed_data';
|
||||
import 'package:flutter_image_compress/flutter_image_compress.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:logger/logger.dart';
|
||||
import 'package:marco/helpers/services/app_logger.dart';
|
||||
|
||||
|
||||
final logger = Logger();
|
||||
|
||||
Future<Uint8List?> compressImageToUnder100KB(File file) async {
|
||||
int quality = 40;
|
||||
@ -24,7 +24,7 @@ Future<Uint8List?> compressImageToUnder100KB(File file) async {
|
||||
);
|
||||
|
||||
if (result != null) {
|
||||
logger.i('Quality: $quality, Size: ${(result.lengthInBytes / 1024).toStringAsFixed(2)} KB');
|
||||
appLogger.i('Quality: $quality, Size: ${(result.lengthInBytes / 1024).toStringAsFixed(2)} KB');
|
||||
|
||||
if (result.lengthInBytes <= 100 * 1024) {
|
||||
return result;
|
||||
|
@ -3,13 +3,15 @@ import 'package:marco/helpers/services/app_initializer.dart';
|
||||
import 'package:marco/view/my_app.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:marco/helpers/theme/app_notifier.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
|
||||
final Logger logger = Logger();
|
||||
import 'package:marco/helpers/services/app_logger.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
await initLogging();
|
||||
|
||||
appLogger.i("App starting...");
|
||||
|
||||
try {
|
||||
await initializeApp();
|
||||
runApp(
|
||||
@ -19,7 +21,8 @@ Future<void> main() async {
|
||||
),
|
||||
);
|
||||
} catch (e, stacktrace) {
|
||||
logger.e('App failed to initialize:', error: e, stackTrace: stacktrace);
|
||||
appLogger.e('App failed to initialize:', error: e, stackTrace: stacktrace);
|
||||
|
||||
runApp(
|
||||
const MaterialApp(
|
||||
home: Scaffold(
|
||||
|
@ -2,10 +2,10 @@ import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:marco/controller/task_planing/add_task_controller.dart';
|
||||
import 'package:marco/helpers/widgets/my_text.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
|
||||
import 'package:marco/helpers/widgets/my_snackbar.dart';
|
||||
|
||||
final Logger log = Logger();
|
||||
|
||||
|
||||
void showCreateTaskBottomSheet({
|
||||
required String workArea,
|
||||
|
@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
|
||||
import 'package:marco/helpers/services/app_logger.dart';
|
||||
import 'package:marco/helpers/extensions/app_localization_delegate.dart';
|
||||
import 'package:marco/helpers/services/auth_service.dart';
|
||||
import 'package:marco/helpers/services/localizations/language.dart';
|
||||
@ -14,7 +14,7 @@ import 'package:marco/helpers/theme/theme_customizer.dart';
|
||||
import 'package:marco/helpers/theme/app_notifier.dart';
|
||||
import 'package:marco/routes.dart';
|
||||
|
||||
final Logger logger = Logger();
|
||||
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
const MyApp({super.key});
|
||||
@ -22,24 +22,24 @@ class MyApp extends StatelessWidget {
|
||||
Future<String> _getInitialRoute() async {
|
||||
try {
|
||||
if (!AuthService.isLoggedIn) {
|
||||
logger.i("User not logged in. Routing to /auth/login-option");
|
||||
appLogger.i("User not logged in. Routing to /auth/login-option");
|
||||
return "/auth/login-option";
|
||||
}
|
||||
|
||||
final bool hasMpin = LocalStorage.getIsMpin();
|
||||
logger.i("MPIN enabled: $hasMpin");
|
||||
appLogger.i("MPIN enabled: $hasMpin");
|
||||
|
||||
if (hasMpin) {
|
||||
await LocalStorage.setBool("mpin_verified", false);
|
||||
logger
|
||||
appLogger
|
||||
.i("Routing to /auth/mpin-auth and setting mpin_verified to false");
|
||||
return "/auth/mpin-auth";
|
||||
} else {
|
||||
logger.i("MPIN not enabled. Routing to /home");
|
||||
appLogger.i("MPIN not enabled. Routing to /home");
|
||||
return "/dashboard";
|
||||
}
|
||||
} catch (e, stacktrace) {
|
||||
logger.e("Error determining initial route",
|
||||
appLogger.e("Error determining initial route",
|
||||
error: e, stackTrace: stacktrace);
|
||||
return "/auth/login-option";
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user