subscription
This commit is contained in:
parent
f70138238b
commit
4a1bd85435
@ -2,13 +2,14 @@ import 'package:flutter/material.dart';
|
||||
import 'package:razorpay_flutter/razorpay_flutter.dart';
|
||||
import 'package:marco/helpers/services/payment_service.dart';
|
||||
import 'package:marco/helpers/services/app_logger.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class PaymentController with ChangeNotifier {
|
||||
Razorpay? _razorpay;
|
||||
final PaymentService _paymentService = PaymentService();
|
||||
|
||||
bool isProcessing = false;
|
||||
BuildContext? _context;
|
||||
//BuildContext? _context;
|
||||
|
||||
/// ==============================
|
||||
/// START PAYMENT (Safe init)
|
||||
@ -18,7 +19,7 @@ class PaymentController with ChangeNotifier {
|
||||
required String description,
|
||||
required BuildContext context,
|
||||
}) async {
|
||||
_context = context;
|
||||
//_context = context;
|
||||
isProcessing = true;
|
||||
notifyListeners();
|
||||
|
||||
@ -39,7 +40,7 @@ class PaymentController with ChangeNotifier {
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
_showError(context, "Failed to connect to server or timeout.");
|
||||
_showError("Failed to connect to server or timeout.");
|
||||
isProcessing = false;
|
||||
notifyListeners();
|
||||
return false;
|
||||
@ -48,7 +49,9 @@ class PaymentController with ChangeNotifier {
|
||||
final orderId = result['data']?['orderId'];
|
||||
final key = result['data']?['key'];
|
||||
if (orderId == null || key == null) {
|
||||
_showError(context, "Invalid response from server.");
|
||||
_showError("Invalid response from server.");
|
||||
logSafe("Invalid response from server.");
|
||||
|
||||
isProcessing = false;
|
||||
notifyListeners();
|
||||
return false;
|
||||
@ -64,7 +67,7 @@ class PaymentController with ChangeNotifier {
|
||||
logSafe("✅ Razorpay instance initialized successfully.");
|
||||
} catch (e) {
|
||||
logSafe("❌ Razorpay init failed: $e", level: LogLevel.error);
|
||||
_showError(context, "Payment system initialization failed.");
|
||||
_showError("Payment system initialization failed.");
|
||||
isProcessing = false;
|
||||
notifyListeners();
|
||||
return false;
|
||||
@ -87,7 +90,7 @@ class PaymentController with ChangeNotifier {
|
||||
return true;
|
||||
} catch (e) {
|
||||
logSafe("❌ Error opening Razorpay: $e", level: LogLevel.error);
|
||||
_showError(context, "Error opening payment gateway.");
|
||||
_showError("Error opening payment gateway.");
|
||||
_cleanup();
|
||||
isProcessing = false;
|
||||
notifyListeners();
|
||||
@ -103,15 +106,17 @@ class PaymentController with ChangeNotifier {
|
||||
isProcessing = true;
|
||||
notifyListeners();
|
||||
|
||||
Map<String, dynamic>? result;
|
||||
Map<String, dynamic>? verificationResult;
|
||||
|
||||
try {
|
||||
result = await _paymentService
|
||||
logSafe("🟢 Verifying payment via backend...");
|
||||
verificationResult = await _paymentService
|
||||
.verifyPayment(
|
||||
paymentId: response.paymentId!,
|
||||
orderId: response.orderId!,
|
||||
signature: response.signature!,
|
||||
)
|
||||
.timeout(const Duration(seconds: 10));
|
||||
.timeout(const Duration(seconds: 15));
|
||||
} catch (e) {
|
||||
logSafe("⏱️ Verification timeout/error: $e", level: LogLevel.error);
|
||||
}
|
||||
@ -119,16 +124,32 @@ class PaymentController with ChangeNotifier {
|
||||
isProcessing = false;
|
||||
notifyListeners();
|
||||
|
||||
if (result != null && result['verified'] == true) {
|
||||
// ✅ Handle backend verification response properly
|
||||
if (verificationResult != null) {
|
||||
// Example backend response: { "verified": true, "message": "Payment verified" }
|
||||
final isVerified = verificationResult['verified'] == true;
|
||||
final msg = verificationResult['message'] ?? '';
|
||||
|
||||
if (isVerified) {
|
||||
_showDialog(
|
||||
title: "Payment Successful 🎉",
|
||||
message: "Your payment was verified successfully.",
|
||||
message:
|
||||
msg.isNotEmpty ? msg : "Your payment was verified successfully.",
|
||||
success: true,
|
||||
);
|
||||
} else {
|
||||
_showDialog(
|
||||
title: "Verification Failed ❌",
|
||||
message: "Payment completed but could not be verified.",
|
||||
message: msg.isNotEmpty
|
||||
? msg
|
||||
: "Payment completed but verification failed.",
|
||||
success: false,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
_showDialog(
|
||||
title: "Verification Failed ❌",
|
||||
message: "Payment completed but backend verification returned null.",
|
||||
success: false,
|
||||
);
|
||||
}
|
||||
@ -162,6 +183,7 @@ class PaymentController with ChangeNotifier {
|
||||
_razorpay?.clear();
|
||||
} catch (_) {}
|
||||
_razorpay = null;
|
||||
logSafe("🧹 Razorpay instance cleaned up.");
|
||||
}
|
||||
|
||||
@override
|
||||
@ -180,36 +202,37 @@ class PaymentController with ChangeNotifier {
|
||||
required String message,
|
||||
required bool success,
|
||||
}) {
|
||||
if (_context == null) return;
|
||||
if (Get.isDialogOpen == true) Get.back(); // Close any existing dialogs
|
||||
|
||||
showDialog(
|
||||
context: _context!,
|
||||
builder: (ctx) => AlertDialog(
|
||||
title: Text(title),
|
||||
content: Text(message),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: const Text("OK"),
|
||||
Get.defaultDialog(
|
||||
title: title,
|
||||
middleText: message,
|
||||
confirm: ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.of(ctx).pop();
|
||||
ScaffoldMessenger.of(_context!).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(success
|
||||
Get.back(); // close dialog
|
||||
Get.snackbar(
|
||||
success ? "Payment Successful 🎉" : "Payment Failed ❌",
|
||||
success
|
||||
? "Payment verified successfully!"
|
||||
: "Payment failed or could not be verified."),
|
||||
: "Payment failed or could not be verified.",
|
||||
backgroundColor: success ? Colors.green : Colors.red,
|
||||
),
|
||||
colorText: Colors.white,
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
child: const Text("OK"),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showError(BuildContext context, String message) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(message), backgroundColor: Colors.red),
|
||||
void _showError(String message) {
|
||||
if (Get.isDialogOpen == true) Get.back(); // Close any open dialog
|
||||
Get.snackbar(
|
||||
"Payment Error",
|
||||
message,
|
||||
backgroundColor: Colors.red,
|
||||
colorText: Colors.white,
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,17 +93,27 @@ class ApiService {
|
||||
|
||||
static dynamic _parseResponse(http.Response response, {String label = ''}) {
|
||||
_log("$label Response: ${response.body}");
|
||||
|
||||
try {
|
||||
final json = jsonDecode(response.body);
|
||||
if (response.statusCode == 200 && json['success'] == true) {
|
||||
return json['data'];
|
||||
final Map<String, dynamic> json = jsonDecode(response.body);
|
||||
|
||||
// ✅ Treat 200–299 range as success
|
||||
final isHttpOk = response.statusCode >= 200 && response.statusCode < 300;
|
||||
final isSuccess = json['success'] == true;
|
||||
|
||||
if (isHttpOk && isSuccess) {
|
||||
return json['data']; // return full data block for use in payment
|
||||
}
|
||||
_log("API Error [$label]: ${json['message'] ?? 'Unknown error'}");
|
||||
|
||||
// ⚠️ Log any API-level error
|
||||
_log(
|
||||
"API Error [$label]: ${json['message'] ?? 'Unknown error'} (code ${response.statusCode})");
|
||||
return null;
|
||||
} catch (e) {
|
||||
_log("Response parsing error [$label]: $e");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static dynamic _parseResponseForAllData(http.Response response,
|
||||
{String label = ''}) {
|
||||
|
||||
@ -21,12 +21,13 @@ class PaymentService {
|
||||
required String signature,
|
||||
}) async {
|
||||
try {
|
||||
logSafe("🟢 Calling verifyPayment API: orderId=$orderId, paymentId=$paymentId");
|
||||
logSafe("🟢 Calling verifyPayment API...");
|
||||
final response = await ApiService.verifyPayment(
|
||||
orderId: orderId,
|
||||
paymentId: paymentId,
|
||||
signature: signature,
|
||||
);
|
||||
logSafe("✅ VerifyPayment API response: $response");
|
||||
return response;
|
||||
} catch (e) {
|
||||
logSafe("❌ Error in verifyPayment: $e", level: LogLevel.error);
|
||||
|
||||
@ -27,22 +27,27 @@ import 'package:marco/view/subscriptions/subscriptions_screen.dart';
|
||||
class AuthMiddleware extends GetMiddleware {
|
||||
@override
|
||||
RouteSettings? redirect(String? route) {
|
||||
// Public routes (no auth required)
|
||||
// ✅ Public routes that don't require authentication
|
||||
const publicRoutes = [
|
||||
'/auth/login-option',
|
||||
'/auth/login',
|
||||
'/subscription', // 👈 Allow this route without auth
|
||||
'/subscription',
|
||||
'/payment',
|
||||
'/select-tenant',
|
||||
];
|
||||
|
||||
// Skip auth checks for public routes
|
||||
if (publicRoutes.contains(route)) return null;
|
||||
// ✅ Allow any route that starts with these public routes
|
||||
if (route != null &&
|
||||
publicRoutes.any((public) => route.startsWith(public))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// ✅ Block others if not logged in
|
||||
if (!AuthService.isLoggedIn) {
|
||||
return const RouteSettings(name: '/auth/login-option');
|
||||
}
|
||||
|
||||
// ✅ Ensure tenant is selected after login
|
||||
if (!TenantService.isTenantSelected) {
|
||||
return const RouteSettings(name: '/select-tenant');
|
||||
}
|
||||
|
||||
@ -303,14 +303,14 @@ class _UserProfileBarState extends State<UserProfileBar>
|
||||
onTap: _onProfileTap,
|
||||
),
|
||||
SizedBox(height: spacingHeight),
|
||||
// _menuItemRow(
|
||||
// icon: LucideIcons.bell,
|
||||
// label: 'Subscribe',
|
||||
// onTap: _onSubscribeTap,
|
||||
// iconColor: Colors.redAccent,
|
||||
// textColor: Colors.redAccent,
|
||||
// ),
|
||||
// SizedBox(height: spacingHeight),
|
||||
_menuItemRow(
|
||||
icon: LucideIcons.bell,
|
||||
label: 'Subscribe',
|
||||
onTap: _onSubscribeTap,
|
||||
iconColor: Colors.redAccent,
|
||||
textColor: Colors.redAccent,
|
||||
),
|
||||
SizedBox(height: spacingHeight),
|
||||
_menuItemRow(
|
||||
icon: LucideIcons.settings,
|
||||
label: 'Settings',
|
||||
@ -380,9 +380,9 @@ class _UserProfileBarState extends State<UserProfileBar>
|
||||
));
|
||||
}
|
||||
|
||||
// void _onSubscribeTap() {
|
||||
// Get.toNamed("/subscription");
|
||||
// }
|
||||
void _onSubscribeTap() {
|
||||
Get.toNamed("/subscription");
|
||||
}
|
||||
|
||||
|
||||
void _onMpinTap() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user