:drunk: Wrote some useless code
This commit is contained in:
@@ -12,13 +12,13 @@ Payment API (`lib/modular/api/payment.dart`) provides a simple interface for min
|
||||
import 'package:island/modular/api/payment.dart';
|
||||
|
||||
// Get singleton instance
|
||||
final paymentAPI = PaymentAPI.instance;
|
||||
final paymentApi = PaymentApi.instance;
|
||||
```
|
||||
|
||||
### Creating a Payment Order
|
||||
|
||||
```dart
|
||||
final order = await paymentAPI.createOrder(
|
||||
final order = await paymentApi.createOrder(
|
||||
CreateOrderRequest(
|
||||
amount: 1000, // $10.00 in cents
|
||||
currency: 'USD',
|
||||
@@ -35,7 +35,7 @@ final orderId = order.id;
|
||||
### Processing Payment with Overlay
|
||||
|
||||
```dart
|
||||
final result = await paymentAPI.processPaymentWithOverlay(
|
||||
final result = await paymentApi.processPaymentWithOverlay(
|
||||
context: context,
|
||||
createOrderRequest: CreateOrderRequest(
|
||||
amount: 1000,
|
||||
@@ -55,7 +55,7 @@ if (result.success) {
|
||||
### Processing Existing Payment
|
||||
|
||||
```dart
|
||||
final result = await paymentAPI.processPaymentWithOverlay(
|
||||
final result = await paymentApi.processPaymentWithOverlay(
|
||||
context: context,
|
||||
request: PaymentRequest(
|
||||
orderId: 'order_123',
|
||||
@@ -71,7 +71,7 @@ final result = await paymentAPI.processPaymentWithOverlay(
|
||||
### Processing Payment Without Overlay (Direct)
|
||||
|
||||
```dart
|
||||
final result = await paymentAPI.processDirectPayment(
|
||||
final result = await paymentApi.processDirectPayment(
|
||||
PaymentRequest(
|
||||
orderId: 'order_123',
|
||||
amount: 1000,
|
||||
@@ -300,33 +300,106 @@ class MiniAppPayment extends StatelessWidget {
|
||||
|
||||
## Integration with flutter_eval
|
||||
|
||||
To expose this API to mini-apps loaded via flutter_eval:
|
||||
### Current Status
|
||||
|
||||
1. Add to plugin registry:
|
||||
**FlutterEval Plugin Initialization: ✅ Complete**
|
||||
- `flutterEvalPlugin` is properly initialized in `lib/modular/miniapp_loader.dart`
|
||||
- Initialized from `main()` during app startup
|
||||
- Plugin is shared between `miniapp_loader.dart` and `lib/modular/registry.dart`
|
||||
- Runtime adds plugin when loading miniapps: `runtime.addPlugin(flutterEvalPlugin)`
|
||||
|
||||
**PaymentBridgePlugin: ✅ Created but not yet registered**
|
||||
- Located at `lib/modular/api/payment_bridge.dart`
|
||||
- Provides simplified wrapper around PaymentApi
|
||||
- Designed for easier integration with eval bridge
|
||||
|
||||
**Full Eval Bridge: ⚠️ Requires Additional Setup**
|
||||
To expose PaymentApi to miniapps through eval, you need to:
|
||||
|
||||
1. **Create EvalPlugin Implementation**
|
||||
```dart
|
||||
// In a new file: lib/modular/api/payment_eval_plugin.dart
|
||||
import 'package:dart_eval/dart_eval_bridge.dart';
|
||||
import 'package:island/modular/api/payment.dart';
|
||||
import 'package:island/modular/api/payment_bridge.dart';
|
||||
|
||||
class PaymentEvalPlugin implements EvalPlugin {
|
||||
@override
|
||||
String get identifier => 'package:island/modular/api/payment.dart';
|
||||
|
||||
@override
|
||||
void configureForCompile(BridgeDeclarationRegistry registry) {
|
||||
// Define bridge classes for PaymentRequest, PaymentResult, CreateOrderRequest
|
||||
// Requires using @Bind() annotations or manual bridge definition
|
||||
}
|
||||
|
||||
@override
|
||||
void configureForRuntime(Runtime runtime) {
|
||||
// Register functions that miniapps can call
|
||||
// This requires bridge wrapper classes to be generated or created manually
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. **Generate or Create Bridge Code**
|
||||
- Option A: Use `dart_eval_annotation` package with `@Bind()` annotations
|
||||
- Add annotations to PaymentApi classes
|
||||
- Run `dart run build_runner build` to generate bridge code
|
||||
- Option B: Manually create bridge wrapper classes
|
||||
- Define `$PaymentRequest`, `$PaymentResult`, etc.
|
||||
- Implement `$Instance` interface for each
|
||||
- Register bridge functions in `configureForRuntime`
|
||||
|
||||
3. **Register Plugin in Registry**
|
||||
```dart
|
||||
// In lib/modular/registry.dart
|
||||
import 'package:island/modular/api/payment.dart';
|
||||
import 'package:island/modular/api/payment_eval_plugin.dart';
|
||||
|
||||
Future<PluginLoadResult> loadMiniApp(...) async {
|
||||
// ... existing code ...
|
||||
|
||||
|
||||
final runtime = Runtime(ByteData.sublistView(bytecode));
|
||||
runtime.addPlugin(flutterEvalPlugin);
|
||||
|
||||
// Register Payment API
|
||||
final paymentAPI = PaymentAPI.instance;
|
||||
// You'll need to create a bridge to expose this to eval
|
||||
|
||||
runtime.addPlugin(PaymentEvalPlugin()); // Add payment API plugin
|
||||
|
||||
// ... rest of loading code
|
||||
}
|
||||
```
|
||||
|
||||
2. Mini-app can access API:
|
||||
4. **Mini-app Usage**
|
||||
```dart
|
||||
// mini_app/main.dart
|
||||
final paymentAPI = PaymentAPI.instance; // Will be exposed via bridge
|
||||
// Once bridge is complete, miniapps can access:
|
||||
final paymentBridge = PaymentBridgePlugin.instance;
|
||||
final result = await paymentBridge.processDirectPayment(
|
||||
orderId: 'order_123',
|
||||
amount: 1000,
|
||||
currency: 'USD',
|
||||
pinCode: '123456',
|
||||
);
|
||||
```
|
||||
|
||||
### Simplified Alternative
|
||||
|
||||
For quick testing without full bridge setup, miniapps can use the example pattern:
|
||||
|
||||
```dart
|
||||
// Simulate API calls in miniapp for testing
|
||||
Future<void> _testPayment() async {
|
||||
setState(() => _isLoading = true);
|
||||
try {
|
||||
await Future.delayed(const Duration(seconds: 2));
|
||||
setState(() => _status = 'Payment successful!');
|
||||
} catch (e) {
|
||||
setState(() => _status = 'Payment failed: $e');
|
||||
} finally {
|
||||
setState(() => _isLoading = false);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This pattern is demonstrated in `packages/miniapp-example/lib/main.dart`.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- **Never hardcode PIN codes**: Always get from user input
|
||||
|
||||
@@ -59,16 +59,16 @@ sealed class CreateOrderRequest with _$CreateOrderRequest {
|
||||
_$CreateOrderRequestFromJson(json);
|
||||
}
|
||||
|
||||
class PaymentAPI {
|
||||
static PaymentAPI? _instance;
|
||||
late Dio _dio;
|
||||
class PaymentApi {
|
||||
static PaymentApi? _instance;
|
||||
late Dio? _dio;
|
||||
late String _serverUrl;
|
||||
String? _token;
|
||||
|
||||
PaymentAPI._internal();
|
||||
PaymentApi._internal();
|
||||
|
||||
static PaymentAPI get instance {
|
||||
_instance ??= PaymentAPI._internal();
|
||||
static PaymentApi get instance {
|
||||
_instance ??= PaymentApi._internal();
|
||||
return _instance!;
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ class PaymentAPI {
|
||||
|
||||
final tokenString = prefs.getString(kTokenPairStoreKey);
|
||||
if (tokenString != null) {
|
||||
final appToken = AppToken.fromJson(jsonDecode(tokenString!));
|
||||
final appToken = AppToken.fromJson(jsonDecode(tokenString));
|
||||
_token = await getToken(appToken);
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ class PaymentAPI {
|
||||
),
|
||||
);
|
||||
|
||||
_dio.interceptors.add(
|
||||
_dio?.interceptors.add(
|
||||
InterceptorsWrapper(
|
||||
onRequest: (options, handler) async {
|
||||
if (_token != null) {
|
||||
@@ -113,7 +113,8 @@ class PaymentAPI {
|
||||
await _initialize();
|
||||
|
||||
try {
|
||||
final response = await _dio.post('/pass/orders', data: request.toJson());
|
||||
if (_dio == null) return null;
|
||||
final response = await _dio!.post('/pass/orders', data: request.toJson());
|
||||
|
||||
return SnWalletOrder.fromJson(response.data);
|
||||
} catch (e) {
|
||||
@@ -129,7 +130,8 @@ class PaymentAPI {
|
||||
await _initialize();
|
||||
|
||||
try {
|
||||
final response = await _dio.post(
|
||||
if (_dio == null) return null;
|
||||
final response = await _dio!.post(
|
||||
'/pass/orders/$orderId/pay',
|
||||
data: {'pin_code': pinCode},
|
||||
);
|
||||
@@ -164,13 +166,13 @@ class PaymentAPI {
|
||||
order = SnWalletOrder(
|
||||
id: request!.orderId,
|
||||
status: 0,
|
||||
currency: request!.currency,
|
||||
remarks: request!.remarks,
|
||||
currency: request.currency,
|
||||
remarks: request.remarks,
|
||||
appIdentifier: 'mini-app',
|
||||
meta: {},
|
||||
amount: request!.amount,
|
||||
amount: request.amount,
|
||||
expiredAt: DateTime.now().add(const Duration(hours: 1)),
|
||||
payeeWalletId: request!.payeeWalletId,
|
||||
payeeWalletId: request.payeeWalletId,
|
||||
transactionId: null,
|
||||
issuerAppId: null,
|
||||
createdAt: DateTime.now(),
|
||||
@@ -179,6 +181,7 @@ class PaymentAPI {
|
||||
);
|
||||
}
|
||||
|
||||
if (!context.mounted) throw PaymentResult(success: false);
|
||||
final result = await PaymentOverlay.show(
|
||||
context: context,
|
||||
order: order,
|
||||
@@ -198,9 +201,7 @@ class PaymentAPI {
|
||||
return PaymentResult(
|
||||
success: false,
|
||||
error: errorMessage,
|
||||
errorCode: e is DioException
|
||||
? (e as DioException).response?.statusCode.toString()
|
||||
: null,
|
||||
errorCode: e is DioException ? e.response?.statusCode.toString() : null,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -232,16 +233,14 @@ class PaymentAPI {
|
||||
return PaymentResult(
|
||||
success: false,
|
||||
error: errorMessage,
|
||||
errorCode: e is DioException
|
||||
? (e as DioException).response?.statusCode.toString()
|
||||
: null,
|
||||
errorCode: e is DioException ? e.response?.statusCode.toString() : null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _parsePaymentError(dynamic error) {
|
||||
if (error is DioException) {
|
||||
final dioError = error as DioException;
|
||||
final dioError = error;
|
||||
|
||||
if (dioError.response?.statusCode == 403 ||
|
||||
dioError.response?.statusCode == 401) {
|
||||
@@ -261,17 +260,18 @@ class PaymentAPI {
|
||||
}
|
||||
|
||||
Future<void> updateServerUrl() async {
|
||||
if (_dio == null) return;
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
_serverUrl =
|
||||
prefs.getString(kNetworkServerStoreKey) ?? kNetworkServerDefault;
|
||||
_dio.options.baseUrl = _serverUrl;
|
||||
_dio!.options.baseUrl = _serverUrl;
|
||||
}
|
||||
|
||||
Future<void> updateToken() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final tokenString = prefs.getString(kTokenPairStoreKey);
|
||||
if (tokenString != null) {
|
||||
final appToken = AppToken.fromJson(jsonDecode(tokenString!));
|
||||
final appToken = AppToken.fromJson(jsonDecode(tokenString));
|
||||
_token = await getToken(appToken);
|
||||
} else {
|
||||
_token = null;
|
||||
@@ -279,6 +279,6 @@ class PaymentAPI {
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_dio.close();
|
||||
_dio?.close();
|
||||
}
|
||||
}
|
||||
|
||||
82
lib/modular/api/payment_bridge.dart
Normal file
82
lib/modular/api/payment_bridge.dart
Normal file
@@ -0,0 +1,82 @@
|
||||
import 'package:island/modular/api/payment.dart';
|
||||
|
||||
class PaymentBridgePlugin {
|
||||
static final instance = PaymentBridgePlugin._internal();
|
||||
PaymentBridgePlugin._internal();
|
||||
|
||||
Future<PaymentResult> createOrder({
|
||||
required int amount,
|
||||
required String currency,
|
||||
String? remarks,
|
||||
String? payeeWalletId,
|
||||
String? appIdentifier,
|
||||
Map<String, dynamic>? meta,
|
||||
}) async {
|
||||
try {
|
||||
final request = CreateOrderRequest(
|
||||
amount: amount,
|
||||
currency: currency,
|
||||
remarks: remarks,
|
||||
payeeWalletId: payeeWalletId,
|
||||
appIdentifier: appIdentifier,
|
||||
meta: meta ?? {},
|
||||
);
|
||||
final order = await PaymentApi.instance.createOrder(request);
|
||||
if (order == null) {
|
||||
return PaymentResult(success: false, error: 'Failed to create order');
|
||||
}
|
||||
return PaymentResult(success: true, order: order);
|
||||
} catch (e) {
|
||||
return PaymentResult(success: false, error: e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Future<PaymentResult> processPayment({
|
||||
required String orderId,
|
||||
required String pinCode,
|
||||
bool enableBiometric = true,
|
||||
}) async {
|
||||
try {
|
||||
final order = await PaymentApi.instance.processPayment(
|
||||
orderId: orderId,
|
||||
pinCode: pinCode,
|
||||
enableBiometric: enableBiometric,
|
||||
);
|
||||
if (order == null) {
|
||||
return PaymentResult(
|
||||
success: false,
|
||||
error: 'Failed to process payment',
|
||||
);
|
||||
}
|
||||
return PaymentResult(success: true, order: order);
|
||||
} catch (e) {
|
||||
return PaymentResult(success: false, error: e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Future<PaymentResult> processDirectPayment({
|
||||
required String orderId,
|
||||
required int amount,
|
||||
required String currency,
|
||||
required String pinCode,
|
||||
String? remarks,
|
||||
String? payeeWalletId,
|
||||
bool enableBiometric = true,
|
||||
}) async {
|
||||
try {
|
||||
final request = PaymentRequest(
|
||||
orderId: orderId,
|
||||
amount: amount,
|
||||
currency: currency,
|
||||
remarks: remarks,
|
||||
payeeWalletId: payeeWalletId,
|
||||
pinCode: pinCode,
|
||||
showOverlay: false,
|
||||
enableBiometric: enableBiometric,
|
||||
);
|
||||
return await PaymentApi.instance.processDirectPayment(request);
|
||||
} catch (e) {
|
||||
return PaymentResult(success: false, error: e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user