Skip to main content

Flutter Helpers

Flutter payment integration helpers for Flutterwave payment processing in the WorkPayCore frontend application.

Configuration Constants

flutterCustomizations

Default customization settings for Flutterwave payment modal.

Properties:

  • title (string): Payment modal title
  • description (string): Payment description
  • logo (string): Logo URL for payment modal

Example:

import { flutterCustomizations } from '@/utils/flutterHelpers';

console.log(flutterCustomizations);
// Returns: {
// title: 'Workpay Africa Limited',
// description: 'Workpay Wallet top up',
// logo: 'https://st2.depositphotos.com/4403291/7418/v/450/depositphotos_74189661-stock-illustration-online-shop-log.jpg'
// }

Use Cases:

  • Consistent branding across payment modals
  • Flutterwave payment configuration
  • Wallet top-up customization

flutterPaymentOptions

Supported payment methods for Flutterwave integration.

Type: string

Value: 'card,mobilemoney,ussd'

Example:

import { flutterPaymentOptions } from '@/utils/flutterHelpers';

const paymentConfig = {
public_key: process.env.VITE_FLUTTER_PUB_KEY,
payment_options: flutterPaymentOptions,
// ... other config
};

Use Cases:

  • Limiting available payment methods
  • Flutterwave payment configuration
  • Regional payment preferences

Utility Functions

closeFlutterPaymentModal()

Programmatically closes the Flutterwave payment modal and restores page scrolling.

Parameters:

  • None

Returns:

  • void: No return value

Example:

import { closeFlutterPaymentModal } from '@/utils/flutterHelpers';

// Close modal after successful payment
const handlePaymentSuccess = () => {
closeFlutterPaymentModal();
showSuccessMessage('Payment completed successfully!');
};

// Close modal on payment error
const handlePaymentError = () => {
closeFlutterPaymentModal();
showErrorMessage('Payment failed. Please try again.');
};

Use Cases:

  • Manual modal closure after payment
  • Error handling in payment flows
  • Custom payment completion handling

Integration Examples

Basic Flutterwave Setup

import { useFlutterwave } from 'flutterwave-react-v3';
import {
flutterCustomizations,
flutterPaymentOptions,
closeFlutterPaymentModal,
} from '@/utils/flutterHelpers';

const PaymentComponent = ({ amount, customerData }) => {
const config = {
public_key: import.meta.env.VITE_FLUTTER_PUB_KEY,
tx_ref: Date.now().toString(),
amount: Number(amount),
currency: 'KES',
payment_options: flutterPaymentOptions,
customer: {
email: customerData.email,
phone_number: customerData.phone,
name: customerData.name,
},
customizations: flutterCustomizations,
};

const handleFlutterPayment = useFlutterwave(config);

return (
<button
onClick={() => {
handleFlutterPayment({
callback: response => {
console.log('Payment Response:', response);
closeFlutterPaymentModal();
},
onClose: () => {
console.log('Payment modal closed');
},
});
}}
>
Pay with Flutterwave
</button>
);
};

Wallet Top-Up Implementation

import {
flutterCustomizations,
flutterPaymentOptions,
closeFlutterPaymentModal,
} from '@/utils/flutterHelpers';

const WalletTopUp = ({ walletId, user }) => {
const [amount, setAmount] = useState('');
const [loading, setLoading] = useState(false);

const config = {
public_key: import.meta.env.VITE_FLUTTER_PUB_KEY,
tx_ref: `wallet_topup_${Date.now()}`,
amount: Number(amount),
currency: 'KES',
payment_options: flutterPaymentOptions,
customer: {
email: user.email,
phone_number: user.phone,
name: `${user.first_name} ${user.last_name}`,
},
customizations: {
...flutterCustomizations,
description: `Wallet top-up for ${user.first_name}`,
},
meta: {
wallet_id: walletId,
user_id: user.id,
},
};

const handleFlutterPayment = useFlutterwave(config);

const initiatePayment = () => {
if (!amount || Number(amount) <= 0) {
alert('Please enter a valid amount');
return;
}

setLoading(true);
handleFlutterPayment({
callback: async response => {
try {
// Process successful payment
await processTopUp({
transaction_id: response.transaction_id,
amount: response.amount,
wallet_id: walletId,
});

closeFlutterPaymentModal();
showSuccessMessage('Wallet topped up successfully!');
} catch (error) {
console.error('Top-up processing failed:', error);
showErrorMessage('Payment processing failed');
} finally {
setLoading(false);
}
},
onClose: () => {
setLoading(false);
console.log('Payment modal closed');
},
});
};

return (
<div className='wallet-topup'>
<input
type='number'
value={amount}
onChange={e => setAmount(e.target.value)}
placeholder='Enter amount'
min='1'
/>
<button onClick={initiatePayment} disabled={loading}>
{loading ? 'Processing...' : 'Top Up Wallet'}
</button>
</div>
);
};

Payment with Error Handling

import {
flutterCustomizations,
closeFlutterPaymentModal,
} from '@/utils/flutterHelpers';

const PaymentWithErrorHandling = () => {
const handlePaymentCallback = response => {
try {
if (response.status === 'successful') {
// Handle successful payment
console.log('Payment successful:', response);
processSuccessfulPayment(response);
} else if (response.status === 'cancelled') {
// Handle cancelled payment
console.log('Payment cancelled by user');
showInfoMessage('Payment was cancelled');
} else {
// Handle failed payment
console.log('Payment failed:', response);
showErrorMessage('Payment failed. Please try again.');
}
} catch (error) {
console.error('Payment processing error:', error);
showErrorMessage('An error occurred while processing payment');
} finally {
closeFlutterPaymentModal();
}
};

const config = {
// ... payment config
customizations: flutterCustomizations,
};

const handleFlutterPayment = useFlutterwave(config);

return (
<button
onClick={() => {
handleFlutterPayment({
callback: handlePaymentCallback,
onClose: () => {
console.log('Modal closed without payment');
},
});
}}
>
Pay Now
</button>
);
};

Custom Payment Modal Styling

import { closeFlutterPaymentModal } from '@/utils/flutterHelpers';

const CustomPaymentModal = () => {
// Custom styling for Flutterwave modal
useEffect(() => {
const styleFlutterModal = () => {
const modal = document.getElementsByName('checkout')[0];
if (modal) {
modal.style.borderRadius = '12px';
modal.style.boxShadow = '0 25px 50px -12px rgba(0, 0, 0, 0.25)';
}
};

// Apply styling when modal opens
const observer = new MutationObserver(styleFlutterModal);
observer.observe(document.body, { childList: true, subtree: true });

return () => observer.disconnect();
}, []);

const customCloseModal = () => {
// Custom close logic
savePaymentAttempt();
trackPaymentCancellation();
closeFlutterPaymentModal();
};

// ... rest of component
};

How closeFlutterPaymentModal Works

The function manipulates the Flutterwave checkout iframe to hide it:

  1. Finds the checkout iframe: document.getElementsByName('checkout')[0]
  2. Hides the modal: Sets styles to make it invisible and non-interactive
  3. Restores scroll: Removes overflow: hidden from document body

Manual Modal Control

// Show modal (if you need to re-show)
const showFlutterModal = () => {
const modal = document.getElementsByName('checkout')[0];
if (modal) {
modal.setAttribute(
'style',
'position:fixed;top:0;left:0;z-index:9999;border:none;opacity:1;pointer-events:auto;width:100%;height:100%;',
);
document.body.style.overflow = 'hidden';
}
};

// Check if modal is open
const isFlutterModalOpen = () => {
const modal = document.getElementsByName('checkout')[0];
return modal && modal.style.opacity !== '0';
};

Environment Configuration

Required Environment Variables

# .env file
VITE_FLUTTER_PUB_KEY=FLWPUBK_TEST-your-public-key-here
# Use FLWPUBK_LIVE for production

Environment-Specific Setup

import { flutterCustomizations } from '@/utils/flutterHelpers';

const getFlutterConfig = (environment = 'development') => {
const baseConfig = {
customizations: flutterCustomizations,
payment_options: 'card,mobilemoney,ussd',
};

if (environment === 'production') {
return {
...baseConfig,
public_key: import.meta.env.VITE_FLUTTER_PUB_KEY_LIVE,
};
}

return {
...baseConfig,
public_key: import.meta.env.VITE_FLUTTER_PUB_KEY,
};
};

Best Practices

  1. Always close modals: Use closeFlutterPaymentModal() in success/error callbacks
  2. Handle all payment states: Success, failure, and cancellation
  3. Validate amounts: Check payment amounts before initiating
  4. Secure keys: Never expose private keys in frontend code
  5. Error logging: Log payment attempts for debugging
  6. User feedback: Provide clear payment status messages

Performance Considerations

  • Modal cleanup: Always close modals to prevent memory leaks
  • Event listeners: Remove event listeners when components unmount
  • Network timeouts: Handle slow network conditions gracefully


TypeScript Definitions

interface FlutterCustomizations {
title: string;
description: string;
logo: string;
}

export const flutterCustomizations: FlutterCustomizations;
export const flutterPaymentOptions: string;
export function closeFlutterPaymentModal(): void;

Dependencies

  • flutterwave-react-v3: React wrapper for Flutterwave
  • DOM API: For modal manipulation
  • Environment variables: For API keys and configuration