payracle_sdk 0.0.1 copy "payracle_sdk: ^0.0.1" to clipboard
payracle_sdk: ^0.0.1 copied to clipboard

Official Flutter SDK for Payracle - integrating payment links, virtual accounts, and checkout interfaces easily.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:payracle_sdk/payracle_sdk.dart';

void main() {
  runApp(const PayracleDemoApp());
}

class PayracleDemoApp extends StatelessWidget {
  const PayracleDemoApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Payracle SDK Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: const Color(0xFF0F172A), // Slate
          primary: const Color(0xFF1E293B),
          secondary: const Color(0xFF10B981), // Emerald
        ),
        useMaterial3: true,
      ),
      home: const DemoHomeScreen(),
    );
  }
}

class DemoHomeScreen extends StatefulWidget {
  const DemoHomeScreen({super.key});

  @override
  State<DemoHomeScreen> createState() => _DemoHomeScreenState();
}

class _DemoHomeScreenState extends State<DemoHomeScreen> {
  final _formKey = GlobalKey<FormState>();
  
  // Text controllers
  final _keyController = TextEditingController(text: 'pk_live_9f2af6692ba552be5e9fdd0f16fc8d247513dc5a');
  final _bizIdController = TextEditingController(text: 'biz_e4ae00bd97f98597b28ec801c22336c2');
  final _urlController = TextEditingController(text: 'https://api.payracle.com/api');
  final _amountController = TextEditingController(text: '1500');
  final _emailController = TextEditingController(text: 'customer@example.com');
  final _titleController = TextEditingController(text: 'Order #9928');
  final _descController = TextEditingController(text: 'Payment for running shoes');

  bool _isLoading = false;

  @override
  void dispose() {
    _keyController.dispose();
    _bizIdController.dispose();
    _urlController.dispose();
    _amountController.dispose();
    _emailController.dispose();
    _titleController.dispose();
    _descController.dispose();
    super.dispose();
  }

  Future<void> _startCheckout() async {
    if (!_formKey.currentState!.validate()) return;

    setState(() {
      _isLoading = true;
    });

    final client = PayracleClient(
      apiKey: _keyController.text.trim(),
      businessId: _bizIdController.text.trim().isEmpty ? null : _bizIdController.text.trim(),
      baseUrl: _urlController.text.trim(),
    );

    final request = CheckoutRequest(
      amount: double.parse(_amountController.text.trim()),
      email: _emailController.text.trim(),
      title: _titleController.text.trim(),
      description: _descController.text.trim(),
      amountControl: 'Fixed',
      validFor: 900, // 15 mins
    );

    try {
      final response = await client.initializeCheckout(request);
      
      setState(() {
        _isLoading = false;
      });

      if (!mounted) return;

      // Show bottom sheet
      await PayracleCheckoutSheet.show(
        context: context,
        client: client,
        checkoutData: response.data,
        onSuccess: (verifyResponse) {
          _showResultDialog(verifyResponse);
        },
        onCancelled: () {
          ScaffoldMessenger.of(context).showSnackBar(
            const SnackBar(
              content: Text('Payment Cancelled by user'),
              backgroundColor: Colors.redAccent,
            ),
          );
        },
      );
    } catch (e) {
      setState(() {
        _isLoading = false;
      });
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text('Checkout Initialization Failed: $e'),
          backgroundColor: Colors.redAccent,
        ),
      );
    }
  }

  void _showResultDialog(VerifyResponse verification) {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Row(
          children: [
            Icon(Icons.check_circle, color: Colors.green),
            SizedBox(width: 8),
            Text('Payment Complete'),
          ],
        ),
        content: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('Reference: ${verification.data.reference}'),
            const SizedBox(height: 4),
            Text('Amount: ₦${verification.data.amount.toStringAsFixed(2)}'),
            const SizedBox(height: 4),
            Text('Payer: ${verification.data.payerEmail ?? "N/A"}'),
            const SizedBox(height: 4),
            Text('Sender Name: ${verification.data.senderName ?? "Sandbox Tester"}'),
            const SizedBox(height: 4),
            Text('Sender Bank: ${verification.data.senderBank ?? "Payracle Sandbox Bank"}'),
          ],
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(),
            child: const Text('OK'),
          )
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xFFF8FAFC), // Slate 50
      appBar: AppBar(
        title: const Text(
          'Payracle SDK Demo',
          style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
        ),
        centerTitle: true,
        backgroundColor: const Color(0xFF0F172A), // Slate 900
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(24.0),
        child: Form(
          key: _formKey,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              // Header
              const Text(
                'Checkout Simulation',
                style: TextStyle(
                  fontSize: 22,
                  fontWeight: FontWeight.bold,
                  color: Color(0xFF0F172A),
                ),
              ),
              const SizedBox(height: 8),
              Text(
                'Configure API options below to test the checkout bottom sheet.',
                style: TextStyle(color: Colors.grey[600], fontSize: 14),
              ),
              const SizedBox(height: 24),

              // API settings card
              Card(
                color: Colors.white,
                surfaceTintColor: Colors.transparent,
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(16),
                  side: BorderSide(color: Colors.grey[200]!),
                ),
                child: Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      const Text(
                        'SDK Configuration',
                        style: TextStyle(
                          fontSize: 15,
                          fontWeight: FontWeight.bold,
                          color: Color(0xFF0F172A),
                        ),
                      ),
                      const SizedBox(height: 16),
                      TextFormField(
                        controller: _keyController,
                        decoration: const InputDecoration(
                          labelText: 'API Key (pk_test_... or sk_test_...)',
                          border: OutlineInputBorder(),
                        ),
                        validator: (value) =>
                            value == null || value.isEmpty ? 'API Key is required' : null,
                      ),
                      const SizedBox(height: 14),
                      TextFormField(
                        controller: _bizIdController,
                        decoration: const InputDecoration(
                          labelText: 'Business ID (Required for Public Keys)',
                          border: OutlineInputBorder(),
                        ),
                      ),
                      const SizedBox(height: 14),
                      TextFormField(
                        controller: _urlController,
                        decoration: const InputDecoration(
                          labelText: 'API Base URL',
                          border: OutlineInputBorder(),
                        ),
                        validator: (value) =>
                            value == null || value.isEmpty ? 'Base URL is required' : null,
                      ),
                    ],
                  ),
                ),
              ),
              const SizedBox(height: 16),

              // Transaction details card
              Card(
                color: Colors.white,
                surfaceTintColor: Colors.transparent,
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(16),
                  side: BorderSide(color: Colors.grey[200]!),
                ),
                child: Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      const Text(
                        'Transaction Info',
                        style: TextStyle(
                          fontSize: 15,
                          fontWeight: FontWeight.bold,
                          color: Color(0xFF0F172A),
                        ),
                      ),
                      const SizedBox(height: 16),
                      TextFormField(
                        controller: _amountController,
                        keyboardType: TextInputType.number,
                        decoration: const InputDecoration(
                          labelText: 'Amount (NGN)',
                          border: OutlineInputBorder(),
                        ),
                        validator: (value) {
                          if (value == null || value.isEmpty) return 'Amount is required';
                          if (double.tryParse(value) == null) return 'Enter a valid number';
                          return null;
                        },
                      ),
                      const SizedBox(height: 14),
                      TextFormField(
                        controller: _emailController,
                        keyboardType: TextInputType.emailAddress,
                        decoration: const InputDecoration(
                          labelText: 'Payer Email',
                          border: OutlineInputBorder(),
                        ),
                        validator: (value) =>
                            value == null || value.isEmpty ? 'Email is required' : null,
                      ),
                      const SizedBox(height: 14),
                      TextFormField(
                        controller: _titleController,
                        decoration: const InputDecoration(
                          labelText: 'Payment Title',
                          border: OutlineInputBorder(),
                        ),
                      ),
                      const SizedBox(height: 14),
                      TextFormField(
                        controller: _descController,
                        decoration: const InputDecoration(
                          labelText: 'Description',
                          border: OutlineInputBorder(),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
              const SizedBox(height: 24),

              // Action button
              ElevatedButton(
                onPressed: _isLoading ? null : _startCheckout,
                style: ElevatedButton.styleFrom(
                  backgroundColor: const Color(0xFF10B981), // Emerald Green
                  foregroundColor: Colors.white,
                  padding: const EdgeInsets.symmetric(vertical: 18),
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(12),
                  ),
                  elevation: 0,
                ),
                child: _isLoading
                    ? const SizedBox(
                        height: 24,
                        width: 24,
                        child: CircularProgressIndicator(
                          strokeWidth: 2.5,
                          valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
                        ),
                      )
                    : const Text(
                        'Initialize Payment Sheet',
                        style: TextStyle(
                          fontSize: 16,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
1
likes
0
points
17
downloads

Publisher

verified publisherpayracle.com

Weekly Downloads

Official Flutter SDK for Payracle - integrating payment links, virtual accounts, and checkout interfaces easily.

Homepage

License

unknown (license)

Dependencies

flutter, http, hugeicons, lottie

More

Packages that depend on payracle_sdk