103 lines
4.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState, useCallback } from 'react';
import { Alert } from 'react-native';
import { useStripe } from '@stripe/stripe-react-native';
import { PlaceOrderResponse, WalletTopUpPaymentSessionResponse } from '@interfaces';
import { verifyPaymentApi } from '@api';
/**
* Custom hook that encapsulates the entire Stripe card payment flow:
* 1. Extract session info from the place-order response
* 2. Initialize the Stripe Payment Sheet
* 3. Present the Payment Sheet to the user
* 4. Verify the payment on the backend via /payments/process
*
* Returns:
* - processCardPayment: async function to run the full flow
* - isPaymentProcessing: loading flag for UI
*/
export const useTopUp = () => {
const { initPaymentSheet, presentPaymentSheet } = useStripe();
const [isPaymentProcessing, setIsPaymentProcessing] = useState(false);
/**
* Runs the complete Stripe card payment flow.
* @param response the PlaceOrderResponse from the backend (contains checkoutSessions)
* @returns `true` if payment was verified successfully, `false` otherwise
*/
const topUpCardPayment = useCallback(
async (response: WalletTopUpPaymentSessionResponse): Promise<boolean> => {
try {
setIsPaymentProcessing(true);
// ── 1. Extract session details ─────────────────────────────────────
// const session = response.checkoutSessions?.[0];
// console.log('session', session);
const clientSecret = response?.gatewayToken;
// console.log('clientSecret', clientSecret);
const gatewayOrderId = response?.gatewayOrderId;
// console.log('gatewayOrderId', gatewayOrderId);
if (!clientSecret) {
Alert.alert('Error', 'Payment session token not found.');
return false;
}
// ── 2. Initialize Payment Sheet ────────────────────────────────────
const { error: initError } = await initPaymentSheet({
paymentIntentClientSecret: clientSecret,
merchantDisplayName: 'SG Delivery',
});
if (initError) {
Alert.alert('Error', `Stripe init failed: ${initError.message}`);
return false;
}
// ── 3. Present Payment Sheet ───────────────────────────────────────
const { error: presentError } = await presentPaymentSheet();
if (presentError) {
if (presentError.code === 'Canceled') {
Alert.alert(
'Payment Cancelled',
'You cancelled the payment process.',
);
} else {
console.log(presentError.message);
Alert.alert('Payment Error', presentError.message);
}
return false;
}
// ── 4. Verify payment on backend ───────────────────────────────────
const verifyRes = await verifyPaymentApi({
gatewayOrderId: gatewayOrderId || '',
gatewayPaymentId: gatewayOrderId || '',
gatewaySignature: 'stripe_signature_verified',
});
if (verifyRes.success) {
return true;
} else {
Alert.alert(
'Verification Failed',
verifyRes.message || 'Unable to confirm payment.',
);
return false;
}
} catch (error: any) {
Alert.alert(
'Payment Error',
error?.message || 'Something went wrong during payment.',
);
return false;
} finally {
setIsPaymentProcessing(false);
}
},
[initPaymentSheet, presentPaymentSheet],
);
return { topUpCardPayment, isPaymentProcessing };
};