payfast_flutter 0.0.6
payfast_flutter: ^0.0.6 copied to clipboard
Flutter SDK for PayFast payment gateway integration with Android, iOS, and Web support.
example/lib/main.dart
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:payfast_flutter/payfast_flutter.dart';
const _merchantId = String.fromEnvironment(
'PAYFAST_MERCHANT_ID',
defaultValue: '241665',
);
const _securedKey = String.fromEnvironment(
'PAYFAST_SECURED_KEY',
defaultValue: '',
);
const _callbackBaseUrl = String.fromEnvironment(
'PAYFAST_CALLBACK_BASE_URL',
defaultValue: 'https://example.com',
);
const _webTokenProxyUrl = String.fromEnvironment(
'PAYFAST_WEB_TOKEN_PROXY_URL',
defaultValue: 'http://127.0.0.1:8080/api/payfast/access-token',
);
String get _webTokenHealthUrl {
final proxyUri = Uri.tryParse(_webTokenProxyUrl);
if (proxyUri == null) {
return 'Invalid PAYFAST_WEB_TOKEN_PROXY_URL';
}
return proxyUri.replace(path: '/api/payfast/health').toString();
}
void main() {
runApp(const PayFastExampleApp());
}
class PayFastExampleApp extends StatelessWidget {
const PayFastExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'PayFast Flutter Example',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
useMaterial3: true,
),
home: const PayFastExamplePage(),
);
}
}
class PayFastExamplePage extends StatefulWidget {
const PayFastExamplePage({super.key});
@override
State<PayFastExamplePage> createState() => _PayFastExamplePageState();
}
class _PayFastExamplePageState extends State<PayFastExamplePage> {
PayFastResult? _lastResult;
String _status = 'Tap the button to start a payment.';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('PayFast Flutter Example')),
body: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 620),
child: ListView(
padding: const EdgeInsets.all(24),
children: [
_InfoCard(
title: 'Simple integration',
child: Text(
kIsWeb
? 'This demo now uses the short PayFast.pay API. On Web, just keep your token proxy running.'
: 'This demo now uses the short PayFast.pay API for Android and iOS.',
),
),
const SizedBox(height: 16),
_InfoCard(
title: 'Configuration',
child: SelectableText(
'merchantId: $_merchantId\n'
'securedKey: ${_securedKey == 'YOUR_SECURED_KEY' ? 'YOUR_SECURED_KEY' : 'Configured via --dart-define'}\n'
'callbackBaseUrl: ${kIsWeb ? Uri.base.origin : _callbackBaseUrl}\n'
'${kIsWeb ? 'webTokenProxy: $_webTokenProxyUrl\nhealthCheck: $_webTokenHealthUrl\nIf token access fails, verify this health URL opens and matches your proxy port.' : 'platform: mobile checkout'}',
),
),
const SizedBox(height: 16),
FilledButton.icon(
onPressed: _startPayment,
icon: const Icon(Icons.payment),
label: const Text('Pay 1000 PKR'),
),
const SizedBox(height: 24),
_InfoCard(
title: 'Last result',
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(_status),
if (_lastResult != null) ...[
const SizedBox(height: 12),
Text(
_lastResult!.success ? 'Status: Success' : 'Status: Failed',
style: TextStyle(
fontWeight: FontWeight.w600,
color: _lastResult!.success ? Colors.green : Colors.red,
),
),
Text('Message: ${_lastResult!.message}'),
Text(
'Transaction ID: ${_lastResult!.transactionId ?? 'N/A'}',
),
],
],
),
),
const SizedBox(height: 16),
const _InfoCard(
title: 'Need help?',
child: SelectableText(
'GitHub: https://github.com/abdullah4445/payfast_flutter\n'
'WhatsApp: https://wa.me/923271774145\n'
'JazzCash support: 03271774145',
),
),
],
),
),
),
);
}
Future<void> _startPayment() async {
if (!mounted) {
return;
}
setState(() {
_status = kIsWeb
? 'Preparing web payment...'
: 'Preparing mobile payment...';
});
await PayFast.pay(
context: context,
merchantId: _merchantId,
securedKey: _securedKey,
basketId: 'ORDER-${DateTime.now().millisecondsSinceEpoch}',
amount: '1000.00',
callbackBaseUrl: _callbackBaseUrl,
txnDesc: 'PayFast Flutter Example Payment',
customerEmail: 'customer@example.com',
customerMobile: '03001234567',
webTokenUrl: _webTokenProxyUrl,
onResult: (result) {
if (!mounted) {
return;
}
setState(() {
_lastResult = result;
_status = result.success
? 'Payment completed successfully.'
: 'Payment did not complete.';
});
},
);
}
}
class _InfoCard extends StatelessWidget {
const _InfoCard({required this.title, required this.child});
final String title;
final Widget child;
@override
Widget build(BuildContext context) {
return Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title, style: Theme.of(context).textTheme.titleMedium),
const SizedBox(height: 8),
child,
],
),
),
);
}
}