mpin add and 2026-04-19 updates

This commit is contained in:
mageshwaran committed 2026-04-19 21:44:01 +05:30
1 parent 41d7cfa8c6
commit 7d25e77138
15 files changed
+2555 -1643

No files matched your search

+7 -1
View File
@@ -2,7 +2,7 @@ class ConstsApi {
static const String baseUrl = "https://www.taxglide.amrithaa.net";
static const String login = "$baseUrl/api/otp/sms/request";
static const String verifyOtp = "$baseUrl/api/otp/sms/verify";
static const String verifyOtp = "$baseUrl/api/otp/email/verify";
static const String signup = "$baseUrl/api/register";
static const String terms = "$baseUrl/api/get_terms_conditions";
static const String policy = "$baseUrl/api/get_privacy_policy";
@@ -28,4 +28,10 @@ class ConstsApi {
static const String dashboard = "$baseUrl/api/get_dashboard_data";
static const String proformaaccept = "$baseUrl/api/proforma/accept";
static const String payNow = "$baseUrl/api/pay_now";
static const String changePin = "$baseUrl/api/change_pin";
static const String loginWithPin = "$baseUrl/api/login";
static const String employeeLoginWithPin = "$baseUrl/api/employee/login";
static const String forgotPassword = "$baseUrl/api/otp/email/request";
static const String employeeForgotPassword = "$baseUrl/api/otp/employee/email/request";
}
+95 -2
View File
@@ -33,6 +33,17 @@ class LoginNotifier extends StateNotifier<AsyncValue<Map<String, dynamic>>> {
LoginNotifier(this._apiRepository) : super(const AsyncValue.data({}));
Future<void> loginWithPin(String email, String pin) async {
if (!mounted) return;
state = const AsyncValue.loading();
try {
final result = await _apiRepository.loginWithPin(email, pin);
if (mounted) state = AsyncValue.data(result);
} catch (e, st) {
if (mounted) state = AsyncValue.error(e, st);
}
}
Future<void> login(String mobile) async {
if (!mounted) return;
state = const AsyncValue.loading();
@@ -86,11 +97,11 @@ class SignupNotifier extends StateNotifier<AsyncValue<Map<String, dynamic>>> {
}
// Verify OTP for signup
Future<void> verifySignupOtp(String mobile, String otp) async {
Future<void> verifySignupOtp(String email, String otp) async {
if (!mounted) return;
state = const AsyncValue.loading();
try {
final result = await _apiRepository.verifySignupOtp(mobile, otp);
final result = await _apiRepository.verifySignupOtp(email, otp);
if (mounted) state = AsyncValue.data(result);
} catch (e, st) {
if (mounted) state = AsyncValue.error(e, st);
@@ -115,6 +126,17 @@ class EmployeeLoginNotifier
EmployeeLoginNotifier(this._apiRepository) : super(const AsyncValue.data({}));
Future<void> loginWithPin(String email, String pin) async {
if (!mounted) return;
state = const AsyncValue.loading();
try {
final result = await _apiRepository.employeeLoginWithPin(email, pin);
if (mounted) state = AsyncValue.data(result);
} catch (e, st) {
if (mounted) state = AsyncValue.error(e, st);
}
}
Future<void> login(String mobile) async {
if (!mounted) return;
state = const AsyncValue.loading();
@@ -137,6 +159,77 @@ class EmployeeLoginNotifier
if (mounted) state = AsyncValue.error(e, st);
}
}
void reset() {
state = const AsyncValue.data({});
}
}
final forgotPasswordProvider =
StateNotifierProvider<
ForgotPasswordNotifier,
AsyncValue<Map<String, dynamic>>
>((ref) => ForgotPasswordNotifier(ref.read(apiRepositoryProvider)));
class ForgotPasswordNotifier
extends StateNotifier<AsyncValue<Map<String, dynamic>>> {
final ApiRepository _apiRepository;
ForgotPasswordNotifier(this._apiRepository)
: super(const AsyncValue.data({}));
Future<void> requestOtp(String email, bool isEmployee) async {
if (!mounted) return;
state = const AsyncValue.loading();
try {
final result = await _apiRepository.requestForgotPasswordOtp(
email,
isEmployee,
);
if (mounted) state = AsyncValue.data(result);
} catch (e, st) {
if (mounted) state = AsyncValue.error(e, st);
}
}
Future<void> verifyOtp(String email, String otp) async {
if (!mounted) return;
state = const AsyncValue.loading();
try {
final result = await _apiRepository.verifyEmailOtp(email, otp);
if (mounted) state = AsyncValue.data(result);
} catch (e, st) {
if (mounted) state = AsyncValue.error(e, st);
}
}
void reset() {
state = const AsyncValue.data({});
}
}
// PIN controller
final changePinProvider =
StateNotifierProvider<PinNotifier, AsyncValue<Map<String, dynamic>>>(
(ref) => PinNotifier(ref.read(apiRepositoryProvider)),
);
class PinNotifier extends StateNotifier<AsyncValue<Map<String, dynamic>>> {
final ApiRepository _apiRepository;
PinNotifier(this._apiRepository) : super(const AsyncValue.data({}));
Future<void> changePin(String pinOrOtp) async {
if (!mounted) return;
state = const AsyncValue.loading();
try {
final result = await _apiRepository.changePin(pinOrOtp);
if (mounted) state = AsyncValue.data(result);
} catch (e, st) {
if (mounted) state = AsyncValue.error(e, st);
}
}
}
final termsProvider = FutureProvider<TermsModel>((ref) async {
+222 -2
View File
@@ -159,6 +159,54 @@ class ApiRepository {
}
}
// 🔹 DIRECT LOGIN (Email + PIN) - ✅ Regenerates FCM token
Future<Map<String, dynamic>> loginWithPin(String email, String pin) async {
try {
final params = {'email': email, 'pin': pin};
// ✅ Regenerate FCM and APNS tokens on every login
final tokens = await _regenerateFcmToken();
final fcmToken = tokens['fcm_token'];
final apnsToken = tokens['apns_token'];
if (fcmToken != null && fcmToken.isNotEmpty) {
params['fcm_token'] = fcmToken;
}
if (apnsToken != null && apnsToken.isNotEmpty) {
params['apns_token'] = apnsToken;
}
if (params['fcm_token'] == null) {
debugPrint('⚠️ Failed to generate FCM token, trying fallback...');
final fallbackToken = await _getFreshFcmToken();
if (fallbackToken != null && fallbackToken.isNotEmpty) {
params['fcm_token'] = fallbackToken;
}
}
final uri = Uri.parse(ConstsApi.loginWithPin).replace(
queryParameters: params.map(
(key, value) => MapEntry(key, value.toString()),
),
);
final response = await http.post(uri, headers: _baseHeaders);
final data = jsonDecode(response.body);
if (response.statusCode == 200 || response.statusCode == 201) {
await _localStore.saveLoginData(data);
return {'success': true, 'data': data};
} else {
return {'success': false, 'error': _extractErrorMessage(data)};
}
} catch (e) {
return {
'success': false,
'error': 'Connection error. Please check your internet.',
};
}
}
// 🔹 VERIFY OTP (LOGIN) - ✅ Regenerates FCM token
Future<Map<String, dynamic>> verifyOtp(LoginModel model) async {
try {
@@ -230,6 +278,143 @@ class ApiRepository {
}
}
// 🔹 EMPLOYEE LOGIN (Email + PIN) - ✅ Regenerates FCM token
Future<Map<String, dynamic>> employeeLoginWithPin(
String email,
String pin,
) async {
try {
final params = {'email': email, 'pin': pin};
// ✅ Regenerate FCM and APNS tokens on every login
final tokens = await _regenerateFcmToken();
final fcmToken = tokens['fcm_token'];
final apnsToken = tokens['apns_token'];
if (fcmToken != null && fcmToken.isNotEmpty) {
params['fcm_token'] = fcmToken;
}
if (apnsToken != null && apnsToken.isNotEmpty) {
params['apns_token'] = apnsToken;
}
if (params['fcm_token'] == null) {
debugPrint('⚠️ Failed to generate FCM token, trying fallback...');
final fallbackToken = await _getFreshFcmToken();
if (fallbackToken != null && fallbackToken.isNotEmpty) {
params['fcm_token'] = fallbackToken;
}
}
final uri = Uri.parse(ConstsApi.employeeLoginWithPin).replace(
queryParameters: params.map(
(key, value) => MapEntry(key, value.toString()),
),
);
final response = await http.post(uri, headers: _baseHeaders);
final data = jsonDecode(response.body);
if (response.statusCode == 200 || response.statusCode == 201) {
await _localStore.saveLoginData(data);
return {'success': true, 'data': data};
} else {
return {'success': false, 'error': _extractErrorMessage(data)};
}
} catch (e) {
return {
'success': false,
'error': 'Connection error. Please check your internet.',
};
}
}
// 🔹 FORGOT PASSWORD REQUEST (Email OTP)
Future<Map<String, dynamic>> requestForgotPasswordOtp(
String email,
bool isEmployee,
) async {
try {
final endpoint = isEmployee
? ConstsApi.employeeForgotPassword
: ConstsApi.forgotPassword;
final uri = Uri.parse(endpoint).replace(queryParameters: {'email': email});
final response = await http.post(uri, headers: _baseHeaders);
final data = jsonDecode(response.body);
if (response.statusCode == 200 || response.statusCode == 201) {
return {'success': true, 'data': data};
} else {
return {'success': false, 'error': _extractErrorMessage(data)};
}
} catch (e) {
return {
'success': false,
'error': 'Connection error. Please check your internet.',
};
}
}
// 🔹 VERIFY EMAIL OTP (Generic)
Future<Map<String, dynamic>> verifyEmailOtp(String email, String otp) async {
try {
final fcmToken = await _getFreshFcmToken();
final uri = Uri.parse(ConstsApi.verifyOtp).replace(
queryParameters: {
'email': email,
'otp': otp,
if (fcmToken != null) 'fcm_token': fcmToken,
},
);
final response = await http.post(uri, headers: _baseHeaders);
final data = jsonDecode(response.body);
if (response.statusCode == 200 || response.statusCode == 201) {
// ✅ CRITICAL: Save login data to get the token for subsequent requests (like set_pin)
await _localStore.saveLoginData(data);
return {'success': true, 'data': data};
} else {
return {'success': false, 'error': _extractErrorMessage(data)};
}
} catch (e) {
return {
'success': false,
'error': 'Connection error. Please check your internet.',
};
}
}
// 🔹 CHANGE/SET PIN
Future<Map<String, dynamic>> changePin(String pin) async {
try {
final token = await _localStore.getToken();
final uri = Uri.parse(ConstsApi.changePin).replace(
queryParameters: {'otp': pin},
);
final response = await http.post(
uri,
headers: {
'Authorization': 'Bearer $token',
'Accept': 'application/json',
},
);
final data = jsonDecode(response.body);
if (response.statusCode == 200 || response.statusCode == 201) {
return {'success': true, 'data': data};
} else {
return {'success': false, 'error': _extractErrorMessage(data)};
}
} catch (e) {
return {
'success': false,
'error': 'Connection error. Please check your internet.',
};
}
}
// 🔹 SIGNUP API
Future<Map<String, dynamic>> signupUser(SignupModel model) async {
try {
@@ -258,7 +443,7 @@ class ApiRepository {
// 🔹 VERIFY OTP (SIGNUP) - ✅ Regenerates FCM token
Future<Map<String, dynamic>> verifySignupOtp(
String mobile,
String email,
String otp,
) async {
try {
@@ -267,7 +452,7 @@ class ApiRepository {
final fcmToken = tokens['fcm_token'];
final apnsToken = tokens['apns_token'];
final params = {'mobile': mobile, 'otp': otp};
final params = {'email': email, 'otp': otp};
if (fcmToken != null && fcmToken.isNotEmpty) {
params['fcm_token'] = fcmToken;
@@ -945,6 +1130,41 @@ debugPrint('📦 KYC Response Body: ${response.body}');
throw {'error': 'Failed to accept proforma: ${e.toString()}'};
}
}
// // 🔹 CHANGE PIN (Verify OTP)
// Future<Map<String, dynamic>> changePin(String otp) async {
// try {
// final token = await _localStore.getToken();
// final uri = Uri.parse(ConstsApi.changePin).replace(
// queryParameters: {'otp': otp},
// );
// final response = await http.post(
// uri,
// headers: {
// 'Authorization': 'Bearer $token',
// 'Accept': 'application/json',
// },
// );
// final data = jsonDecode(response.body);
// debugPrint("🚀 Change Pin (Verify) API Response: $data");
// if (response.statusCode == 200 || response.statusCode == 201) {
// return {'success': true, 'data': data};
// } else {
// return {'success': false, 'error': _extractErrorMessage(data)};
// }
// } catch (e) {
// debugPrint('❌ Change Pin API Error: $e');
// return {
// 'success': false,
// 'error': 'Connection error. Please try again.',
// };
// }
// }
// 🔹 LOGOUT - ✅ Deletes FCM token
Future<void> logout() async {