baseproject
This commit is contained in:
384
base_project/lib/view_model/auth/auth_view_model.dart
Normal file
384
base_project/lib/view_model/auth/auth_view_model.dart
Normal file
@@ -0,0 +1,384 @@
|
||||
import 'dart:async';
|
||||
import 'package:base_project/repository/auth_repo.dart';
|
||||
import 'package:base_project/routes/route_names.dart';
|
||||
import 'package:base_project/utils/flushbar_messages/flush_message_util.dart';
|
||||
import 'package:base_project/utils/managers/user_manager.dart';
|
||||
import 'package:base_project/utils/toast_messages/toast_message_util.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class AuthViewModel extends ChangeNotifier {
|
||||
final AuthRepo _authRepo = AuthRepo();
|
||||
bool _isLoading = false;
|
||||
bool get isLoading => _isLoading;
|
||||
|
||||
setLoading(bool value) {
|
||||
_isLoading = value;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Timer? _timer;
|
||||
int _start = 30;
|
||||
bool _isResendEnabled = false;
|
||||
|
||||
int get start => _start;
|
||||
bool get isResendEnabled => _isResendEnabled;
|
||||
|
||||
void startTimer() {
|
||||
_isResendEnabled = false;
|
||||
_start = 30; // Set the timer duration (in seconds)
|
||||
_timer = Timer.periodic(const Duration(seconds: 1), (Timer timer) {
|
||||
if (_start == 0) {
|
||||
_timer?.cancel();
|
||||
_isResendEnabled = true;
|
||||
notifyListeners();
|
||||
} else {
|
||||
_start--;
|
||||
print(_start);
|
||||
notifyListeners();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var accId = "";
|
||||
var uEmail = "";
|
||||
|
||||
Future<void> login(BuildContext context, dynamic data) async {
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
final value = await _authRepo.loginApi(data);
|
||||
print('Value is -$value');
|
||||
|
||||
// Check the response structure
|
||||
if (value['operationStatus'] == 'SUCCESS') {
|
||||
final item = value['item'];
|
||||
await UserManager().setUser(item);
|
||||
// Try to persist sys account from login response if present
|
||||
try {
|
||||
final dynamic accountCandidate =
|
||||
item['sysAccount'] ?? item['account'] ?? item['sys_account'];
|
||||
if (accountCandidate is Map<String, dynamic>) {
|
||||
await UserManager().setAccount(accountCandidate);
|
||||
}
|
||||
} catch (_) {}
|
||||
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
prefs.setBool('isLoggedIn', true);
|
||||
// Handle successful login
|
||||
ToastMessageUtil.showToast(
|
||||
message: 'Logged in as ${value['item']['email']}',
|
||||
toastType: ToastType.general);
|
||||
// nav to home
|
||||
Navigator.pushReplacementNamed(context, RouteNames.homeView);
|
||||
} else {
|
||||
print('Error got ');
|
||||
|
||||
// Handle login failure with backend message if available
|
||||
final backendMessage = (value is Map)
|
||||
? (value['operationMessage'] ?? value['message'] ?? value['msg'])
|
||||
: null;
|
||||
final message = (backendMessage?.toString().trim().isNotEmpty == true)
|
||||
? backendMessage.toString()
|
||||
: "Failed!! Email or Password is incorrect";
|
||||
|
||||
FlushBarMessageUtil.showFlushBar(
|
||||
context: context,
|
||||
message: message,
|
||||
flushBarType: FlushBarType.error,
|
||||
);
|
||||
}
|
||||
} catch (error, stackTrace) {
|
||||
print("Error -$error");
|
||||
print("st -$stackTrace");
|
||||
// Handle any other errors
|
||||
FlushBarMessageUtil.showFlushBar(
|
||||
context: context,
|
||||
message: error.toString(),
|
||||
flushBarType: FlushBarType.error,
|
||||
);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> signUp(BuildContext context, dynamic data) async {
|
||||
setLoading(true);
|
||||
final createUserData = {...data, 'account_id': accId};
|
||||
print("CreateUserData--$createUserData");
|
||||
|
||||
_authRepo.createUserApi(createUserData).then((value) {
|
||||
print(value);
|
||||
ToastMessageUtil.showToast(
|
||||
message: "Account Created", toastType: ToastType.success);
|
||||
setLoading(false);
|
||||
Navigator.pushReplacementNamed(context, RouteNames.loginView);
|
||||
}).onError(
|
||||
(error, stackTrace) {
|
||||
print(error);
|
||||
print(stackTrace);
|
||||
FlushBarMessageUtil.showFlushBar(
|
||||
context: context,
|
||||
message: error.toString(),
|
||||
flushBarType: FlushBarType.error);
|
||||
setLoading(false);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// New method for combined registration flow (account + user)
|
||||
Future<void> signUpWithAccountCreation(
|
||||
BuildContext context, dynamic data) async {
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
// Step 1: Create account with just email and password
|
||||
final accountData = {
|
||||
"email": data["email"],
|
||||
};
|
||||
|
||||
print("Creating account with data: $accountData");
|
||||
final accountResponse = await _authRepo.createAcApi(accountData);
|
||||
print("Account creation response: $accountResponse");
|
||||
|
||||
// Extract account ID from response
|
||||
final accountId = accountResponse['account_id']?.toString();
|
||||
if (accountId == null) {
|
||||
throw Exception("Account ID not received from server");
|
||||
}
|
||||
|
||||
// Step 2: Create user with account ID
|
||||
final createUserData = {...data, 'account_id': accountId};
|
||||
|
||||
print("Creating user with data: $createUserData");
|
||||
final userResponse = await _authRepo.createUserApi(createUserData);
|
||||
print("User creation response: $userResponse");
|
||||
|
||||
ToastMessageUtil.showToast(
|
||||
message: "Account Created Successfully",
|
||||
toastType: ToastType.success);
|
||||
|
||||
// Navigate to login
|
||||
Navigator.pushReplacementNamed(context, RouteNames.loginView);
|
||||
} catch (error, stackTrace) {
|
||||
print("SignUp error: $error");
|
||||
print("Stack trace: $stackTrace");
|
||||
|
||||
String errorMessage = "Registration failed. Please try again.";
|
||||
if (error.toString().contains('already exist')) {
|
||||
errorMessage = "Email already exists. Please use a different email.";
|
||||
} else if (error.toString().contains('account_id')) {
|
||||
errorMessage = "Account creation failed. Please try again.";
|
||||
}
|
||||
|
||||
FlushBarMessageUtil.showFlushBar(
|
||||
context: context,
|
||||
message: errorMessage,
|
||||
flushBarType: FlushBarType.error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> createAcc(BuildContext context, dynamic data) async {
|
||||
setLoading(true);
|
||||
_authRepo.createAcApi(data).then(
|
||||
(value) {
|
||||
print("Value--$value");
|
||||
accId = value['account_id'].toString();
|
||||
setLoading(false);
|
||||
ToastMessageUtil.showToast(
|
||||
message: "Success creating account", toastType: ToastType.success);
|
||||
// Navigator.pushNamed(context, RouteNames.signUp,arguments: uEmail);
|
||||
},
|
||||
).onError(
|
||||
(error, stackTrace) {
|
||||
print("error--$error");
|
||||
setLoading(false);
|
||||
ToastMessageUtil.showToast(
|
||||
message: "Error registering your account",
|
||||
toastType: ToastType.error);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> getOtp(BuildContext context, dynamic data) async {
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
final value = await _authRepo.getOtpApi(data);
|
||||
print(value);
|
||||
|
||||
// Handle non-exception responses like { msg: "... already exist" }
|
||||
if (value is Map) {
|
||||
final map = Map<String, dynamic>.from(value);
|
||||
final message = (map['msg'] ?? map['message'] ?? '').toString();
|
||||
final operationStatus = (map['operationStatus'] ?? '').toString();
|
||||
final otpSent = (map['otp_sent'] == true) || (map['otpSent'] == true);
|
||||
|
||||
// Block when backend says email already exists
|
||||
if (message.toLowerCase().contains('already exist')) {
|
||||
ToastMessageUtil.showToast(
|
||||
message: 'Email already exists',
|
||||
toastType: ToastType.error,
|
||||
);
|
||||
return; // do not navigate
|
||||
}
|
||||
|
||||
// Consider success scenarios (handle variants like "Otp send successfully")
|
||||
final lowerMsg = message.toLowerCase();
|
||||
final messageLooksSuccess = lowerMsg.contains('otp sent') ||
|
||||
lowerMsg.contains('sent successfully') ||
|
||||
(lowerMsg.contains('otp') && lowerMsg.contains('success')) ||
|
||||
lowerMsg.contains('send successfully');
|
||||
|
||||
if (operationStatus == 'SUCCESS' || otpSent || messageLooksSuccess) {
|
||||
ToastMessageUtil.showToast(
|
||||
message: message.isNotEmpty ? message : 'OTP sent successfully',
|
||||
toastType: ToastType.success,
|
||||
);
|
||||
// Start resend countdown when OTP is sent
|
||||
startTimer();
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
RouteNames.verifyOtpView,
|
||||
arguments: {'email': data['email']},
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback: show backend message if present
|
||||
if (message.isNotEmpty) {
|
||||
ToastMessageUtil.showToast(
|
||||
message: message,
|
||||
toastType: ToastType.error,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Unknown response structure
|
||||
ToastMessageUtil.showToast(
|
||||
message: 'Failed to send OTP',
|
||||
toastType: ToastType.error,
|
||||
);
|
||||
} catch (error) {
|
||||
// Handle any other exceptions
|
||||
print("getOtp error: $error");
|
||||
final msg = error.toString();
|
||||
String uiMessage = 'Failed to send OTP';
|
||||
if (msg.contains('already exist') || msg.contains('already exists')) {
|
||||
uiMessage = 'Email already exists';
|
||||
} else if (msg.contains('invalid') || msg.contains('Invalid')) {
|
||||
uiMessage = 'Invalid email address';
|
||||
} else if (msg.contains('timeout')) {
|
||||
uiMessage = 'Request timed out. Please try again.';
|
||||
}
|
||||
|
||||
ToastMessageUtil.showToast(
|
||||
message: uiMessage,
|
||||
toastType: ToastType.error,
|
||||
);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> resendOtp(BuildContext context, dynamic data) async {
|
||||
startTimer();
|
||||
await _authRepo.resendOtpApi(data).then((value) {
|
||||
print(value);
|
||||
ToastMessageUtil.showToast(
|
||||
message: "OTP resend successfully",
|
||||
toastType: ToastType.success,
|
||||
);
|
||||
}).onError(
|
||||
(error, stackTrace) {
|
||||
print(error);
|
||||
ToastMessageUtil.showToast(
|
||||
message: "Failed to resend OTP",
|
||||
toastType: ToastType.error,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Returns null on success, or a human-readable error message on failure
|
||||
Future<String?> verifyOtp(BuildContext context, dynamic queryParams) async {
|
||||
print("Verifying otp");
|
||||
setLoading(true);
|
||||
try {
|
||||
final value = await _authRepo.verifyOtpApi(queryParams);
|
||||
print(value);
|
||||
|
||||
// Backend returns 200 with EntityResponse("OTP Verified")
|
||||
// and 400 with EntityResponse("Wrong OTP") or MessageResponse("... not exist")
|
||||
if (value is Map) {
|
||||
final map = Map<String, dynamic>.from(value);
|
||||
final message = (map['msg'] ?? map['message'] ?? '').toString();
|
||||
final lower = message.toLowerCase();
|
||||
|
||||
if (lower.contains('otp verified')) {
|
||||
ToastMessageUtil.showToast(
|
||||
message: 'OTP Verified',
|
||||
toastType: ToastType.success,
|
||||
);
|
||||
uEmail = queryParams['email'];
|
||||
cancelTimer();
|
||||
return null;
|
||||
}
|
||||
|
||||
if (lower.contains('wrong otp')) {
|
||||
ToastMessageUtil.showToast(
|
||||
message: 'Wrong OTP',
|
||||
toastType: ToastType.error,
|
||||
);
|
||||
return 'Wrong OTP';
|
||||
}
|
||||
|
||||
if (lower.contains('not exist')) {
|
||||
ToastMessageUtil.showToast(
|
||||
message: 'User not found',
|
||||
toastType: ToastType.error,
|
||||
);
|
||||
return 'User not found';
|
||||
}
|
||||
|
||||
// Fallback: show message if present
|
||||
if (message.isNotEmpty) {
|
||||
ToastMessageUtil.showToast(
|
||||
message: message,
|
||||
toastType: ToastType.error,
|
||||
);
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
ToastMessageUtil.showToast(
|
||||
message: 'OTP verification failed',
|
||||
toastType: ToastType.error,
|
||||
);
|
||||
return 'OTP verification failed';
|
||||
} catch (error) {
|
||||
print(error);
|
||||
ToastMessageUtil.showToast(
|
||||
message: "OTP verification failed",
|
||||
toastType: ToastType.error,
|
||||
);
|
||||
return 'OTP verification failed';
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
void cancelTimer() {
|
||||
_timer?.cancel();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
cancelTimer(); // Ensure the timer is cancelled
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user