zips-react-native-sdk-test
Version:
Lightweight ZIPS Payment Gateway SDK for React Native - Complete payment solution with ZApp wallet payments and Access Bank integration
170 lines (169 loc) • 7.96 kB
JavaScript
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { useState, useCallback, useEffect } from 'react';
import Toast from 'react-native-toast-message';
import { Text, TouchableOpacity, } from 'react-native';
import PaymentModal from './PaymentModal';
import { QueryClientProvider } from '@tanstack/react-query';
import { queryClient } from '../tanstack-query/queryClient';
import { useZipsContext, ZipsProvider } from '../context/ZipsProvider';
import { NetBankingProvider, useNetBankingContext, } from '../context/NetBankingProvider';
import { WalletProvider } from '../context/WalletProvider';
import { CardProvider } from '../context/CardProvider';
import Zips from 'zips-typescript-sdk';
export default function PaymentButton(props) {
return (_jsx(QueryClientProvider, { client: queryClient, children: _jsx(ZipsProvider, { children: _jsx(NetBankingProvider, { children: _jsx(WalletProvider, { children: _jsx(CardProvider, { children: _jsx(PaymentButtonInner, { ...props }) }) }) }) }) }));
}
function PaymentButtonInner({ apiKey, paymentDetails, onSuccess, onError, buttonText = 'Pay Now', environment = 'sandbox', style, children, }) {
const { isLoading, isPaid, order, setTransactionDetails, setZips, setIsLoading, error, setError, transactionDetails, setPaymentMethod, setCurrentStep, } = useZipsContext();
const { resetNetBanking } = useNetBankingContext();
const [showModal, setShowModal] = useState(false);
const handleButtonPress = useCallback(async () => {
if (isLoading)
return;
// Clear error state when starting a new payment attempt
if (error) {
setError(null);
}
// Verify payment details first
const isVerified = await verifyPaymentDetails();
// Only show modal if verification is successful
if (isVerified) {
setShowModal(true);
}
}, [isLoading, error, setError]);
const handleModalClose = useCallback(() => {
// Only reset states, don't clear transaction details that might be needed
setShowModal(false);
resetNetBanking();
setPaymentMethod({});
setCurrentStep('method-selection');
}, []);
// Modern default button styles - compact and elegant
const defaultButtonStyle = {
backgroundColor: '#1D4ED8', // Modern blue
borderRadius: 16, // More rounded
paddingVertical: 14,
paddingHorizontal: 24,
minHeight: 48,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
alignSelf: 'flex-start', // Don't take full width
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 8,
elevation: 4, // Android shadow
};
// Modern text styles
const defaultTextStyle = {
color: '#FFFFFF',
fontSize: 16,
fontWeight: '600',
textAlign: 'center',
letterSpacing: 0.5,
};
// Compute final button styles
const buttonStyle = {
...defaultButtonStyle,
...style, // User style overrides defaults
};
// Default children if none provided
const defaultChildren = _jsx(Text, { style: defaultTextStyle, children: buttonText });
const verifyPaymentDetails = async () => {
setIsLoading(true);
try {
// Perform verification logic here
const zips = new Zips(apiKey);
const payment = await zips.payments.create({
amount: paymentDetails.amount,
currency: paymentDetails.currency || 'GMD',
firstName: paymentDetails.firstName,
lastName: paymentDetails.lastName,
phoneNumber: paymentDetails.phoneNumber,
merchantAccountId: paymentDetails.merchantAccountId,
name: paymentDetails.name,
projectId: paymentDetails.projectId,
quantity: paymentDetails.quantity,
description: paymentDetails.description,
});
if (!payment) {
throw new Error('Payment creation failed');
}
const transaction = await zips.transactions.single(payment === null || payment === void 0 ? void 0 : payment.referenceNumber);
if (!transaction) {
throw new Error('Transaction not found');
}
console.log(transaction === null || transaction === void 0 ? void 0 : transaction.data);
setTransactionDetails(transaction === null || transaction === void 0 ? void 0 : transaction.data);
return true; // Return true on success
}
catch (error) {
console.log('SDK ERROR', error);
// Handle error gracefully
setError(error);
return false; // Return false on error
}
finally {
setIsLoading(false);
}
};
useEffect(() => {
if (apiKey) {
setZips({
apiKey,
paymentDetails,
environment,
});
}
}, [apiKey, environment, paymentDetails]);
useEffect(() => {
if (order) {
Toast.show({
type: 'success',
text1: 'Payment Successful',
text2: `Your payment of ${order.amount} was successful.`,
swipeable: true,
autoHide: true,
avoidKeyboard: true,
visibilityTime: 2000,
});
setTimeout(() => {
onSuccess({
...order,
...transactionDetails,
status: 'success',
});
setShowModal(false);
resetNetBanking();
setPaymentMethod({});
resetNetBanking();
}, 2000);
}
}, [order, onSuccess, resetNetBanking]);
useEffect(() => {
var _a, _b, _c, _d, _e, _f, _g;
if (error) {
// Only show toast for backend errors (not network/axios errors)
const isBackendError = ((_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.status) && ((_b = error === null || error === void 0 ? void 0 : error.response) === null || _b === void 0 ? void 0 : _b.data);
if (isBackendError) {
Toast.show({
type: 'error',
text1: 'Payment Error',
text2: ((_e = (_d = (_c = error === null || error === void 0 ? void 0 : error.response) === null || _c === void 0 ? void 0 : _c.data) === null || _d === void 0 ? void 0 : _d.message) === null || _e === void 0 ? void 0 : _e.toString()) ||
((_g = (_f = error === null || error === void 0 ? void 0 : error.response) === null || _f === void 0 ? void 0 : _f.data) === null || _g === void 0 ? void 0 : _g.toString()) ||
'An error occurred during payment processing',
swipeable: true,
autoHide: true,
avoidKeyboard: true,
});
}
// Always call onError for developer handling
onError(error);
}
}, [error, onError]);
return (_jsxs(_Fragment, { children: [_jsx(TouchableOpacity, { style: {
...buttonStyle,
opacity: isLoading || isPaid ? 0.5 : 1,
}, onPress: handleButtonPress, disabled: isLoading || isPaid, activeOpacity: 0.8, accessibilityRole: "button", accessibilityState: { disabled: isLoading || isPaid }, accessibilityLabel: buttonText, children: isLoading ? (_jsx(Text, { style: defaultTextStyle, children: "Verifying..." })) : (children || defaultChildren) }), _jsx(PaymentModal, { visible: showModal, onClose: handleModalClose })] }));
}