baseproject

This commit is contained in:
Gaurav Kumar
2025-09-06 19:21:52 +05:30
commit 01be9df2ed
254 changed files with 28342 additions and 0 deletions

View 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();
}
}