diff --git a/android/gradle.properties b/android/gradle.properties index 7e36110..e449a3e 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,4 +1,7 @@ -org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError +org.gradle.jvmargs=-Xmx1536m -XX:MaxMetaspaceSize=256m -Dfile.encoding=UTF-8 +org.gradle.parallel=false +org.gradle.workers.max=1 +org.gradle.daemon=false android.useAndroidX=true # This newDsl flag was added by the Flutter template android.newDsl=false diff --git a/lib/core/constants/api_constants.dart b/lib/core/constants/api_constants.dart index 30d2080..2b5292d 100644 --- a/lib/core/constants/api_constants.dart +++ b/lib/core/constants/api_constants.dart @@ -7,6 +7,10 @@ class ApiConstants { static const String verifyPin = '$baseUrl/customer/verify-pin'; static const String resetPin = '$baseUrl/customer/reset-pin'; static const String logout = '$baseUrl/customer/logout'; + + // ---- Email OTP (Replace Firebase) ---- + static const String sendEmailOtp = '$baseUrl/customer/send-email-otp'; + static const String verifyEmailOtp = '$baseUrl/customer/verify-email-otp'; // ---- Profile ---- static const String profile = '$baseUrl/customer/profile'; diff --git a/lib/features/auth/screens/otp_screen.dart b/lib/features/auth/screens/otp_screen.dart index badf76a..2d64db5 100644 --- a/lib/features/auth/screens/otp_screen.dart +++ b/lib/features/auth/screens/otp_screen.dart @@ -30,7 +30,6 @@ class _OtpScreenState extends State { void initState() { super.initState(); _startTimer(); - // Pre-fill demo OTP for the no-backend prototype. WidgetsBinding.instance.addPostFrameCallback((_) => _nodes[0].requestFocus()); } @@ -148,10 +147,10 @@ class _OtpScreenState extends State { height: 88, decoration: const BoxDecoration( color: AppColors.primaryFixed, shape: BoxShape.circle), - child: const Icon(Icons.sms_rounded, size: 40, color: AppColors.primary), + child: const Icon(Icons.mark_email_read_rounded, size: 40, color: AppColors.primary), ), const SizedBox(height: 24), - Text('Verify your number', + Text('Verify your email', textAlign: TextAlign.center, style: AppTheme.headlineLg), const SizedBox(height: 8), Text.rich( @@ -160,7 +159,7 @@ class _OtpScreenState extends State { children: [ const TextSpan(text: 'We sent a 6-digit code to '), TextSpan( - text: '+91 ${phone.isEmpty ? '98111 22334' : phone}', + text: context.read().pendingEmail ?? 'your email', style: AppTheme.labelMd, ), ], @@ -194,9 +193,6 @@ class _OtpScreenState extends State { loading: _loading, onPressed: filled ? _verify : null, ), - const SizedBox(height: 8), - Text('Tip: enter any 6 digits to continue', - style: AppTheme.caption.copyWith(color: AppColors.outline)), ], ), ), diff --git a/lib/shared/state/app_state.dart b/lib/shared/state/app_state.dart index 47741c8..09767aa 100644 --- a/lib/shared/state/app_state.dart +++ b/lib/shared/state/app_state.dart @@ -133,74 +133,44 @@ class AppState extends ChangeNotifier { pendingFirstName = firstName; pendingEmail = email; isResettingPin = resetPin; - - try { - if (kIsWeb) { - debugPrint('⚠️ RUNNING ON WEB: Bypassing Firebase OTP (Mocking success)'); - Future.delayed(const Duration(seconds: 1), () { - verificationId = 'mock_verification_id_$fullPhone'; - onSuccess(); - }); - return; - } - debugPrint('===================================='); - debugPrint('🚀 INITIATING LIVE FIREBASE OTP FOR: $fullPhone'); - await FirebaseAuth.instance.verifyPhoneNumber( - phoneNumber: fullPhone, - verificationCompleted: (PhoneAuthCredential credential) async { - debugPrint('✅ VERIFICATION COMPLETED AUTOMATICALLY'); - try { - await FirebaseAuth.instance.signInWithCredential(credential); - } catch (e) { - debugPrint('❌ ERROR SIGNING IN: $e'); - onError(e.toString()); - } - }, - verificationFailed: (FirebaseAuthException e) { - debugPrint('❌ VERIFICATION FAILED: ${e.code} - ${e.message}'); - onError(e.message ?? 'Verification failed'); - }, - codeSent: (String vId, int? resendToken) { - debugPrint('✅ CODE SUCCESSFULLY SENT. Verification ID: $vId'); - verificationId = vId; - onSuccess(); - }, - codeAutoRetrievalTimeout: (String vId) { - debugPrint('⚠️ AUTO RETRIEVAL TIMEOUT. Verification ID: $vId'); - verificationId = vId; - }, + if (email == null || email.isEmpty) { + onError('Email address is required for verification.'); + return; + } + + try { + final res = await http.post( + Uri.parse(ApiConstants.sendEmailOtp), + headers: {'Content-Type': 'application/json'}, + body: jsonEncode({"email": email, "phone": fullPhone}), ); + + if (res.statusCode >= 200 && res.statusCode < 300) { + onSuccess(); + } else { + final body = jsonDecode(res.body); + onError(body['message'] ?? 'Failed to send verification code.'); + } } catch (e) { - debugPrint('💥 FIREBASE OTP CRASHED COMPLETELY: $e'); - onError('Firebase OTP Error: $e'); + onError('Error: $e'); } } Future verifyOtp(String smsCode, {required Function onSuccess, required Function(String) onError}) async { - if (verificationId == null) { - onError('Verification ID is missing. Please resend OTP.'); - return; - } try { - if (kIsWeb) { - debugPrint('⚠️ RUNNING ON WEB: Bypassing Firebase OTP verification (Mocking success)'); - Future.delayed(const Duration(seconds: 1), () { - if (smsCode.length == 6) { - onSuccess(); - } else { - onError('Invalid mock OTP code (must be 6 digits).'); - } - }); - return; - } - - PhoneAuthCredential credential = PhoneAuthProvider.credential( - verificationId: verificationId!, - smsCode: smsCode, + final res = await http.post( + Uri.parse(ApiConstants.verifyEmailOtp), + headers: {'Content-Type': 'application/json'}, + body: jsonEncode({"email": pendingEmail, "otp": smsCode}), ); - await FirebaseAuth.instance.signInWithCredential(credential); - onSuccess(); + + if (res.statusCode >= 200 && res.statusCode < 300) { + onSuccess(); + } else { + final body = jsonDecode(res.body); + onError(body['message'] ?? 'Invalid verification code.'); + } } catch (e) { onError('Error: $e'); }