a0-purchases
Version:
Lightweight subscription management for AI apps with auto-detecting providers
119 lines • 5.8 kB
JavaScript
import { useState, useEffect, useCallback, useRef } from "react";
import { Platform } from "react-native";
import { useStripe, PaymentSheetError } from "./stripe";
import { registerStripePresenter, createLibraryError, PURCHASES_ERROR_CODE } from "./legacy-compat";
// Rename the component here
export const A0PaymentProvider = () => {
// Early return for iOS - disable all Stripe functionality
if (Platform.OS === 'ios') {
// Register a no-op presenter that rejects all requests on iOS
useEffect(() => {
registerStripePresenter({
requestPresentation: (request) => {
request.reject(createLibraryError("Payment processing is disabled on iOS to comply with App Store guidelines.", PURCHASES_ERROR_CODE.STORE_PROBLEM_ERROR));
},
});
return () => {
registerStripePresenter(null);
};
}, []);
// Return null - no Stripe functionality on iOS
return null;
}
const { initPaymentSheet, presentPaymentSheet } = useStripe();
const [currentRequest, setCurrentRequest] = useState(null);
const [isSheetInitialized, setIsSheetInitialized] = useState(false);
const currentRequestRef = useRef(currentRequest); // Ref to avoid stale closures in callbacks
useEffect(() => {
currentRequestRef.current = currentRequest;
}, [currentRequest]);
// Callback for the service to trigger presentation
const handlePresentationRequest = useCallback((request) => {
// Update log messages
// Ensure no request is already in progress
if (currentRequestRef.current) {
request.reject(createLibraryError("Another Stripe payment presentation is already in progress.", PURCHASES_ERROR_CODE.OPERATION_ALREADY_IN_PROGRESS_ERROR));
return;
}
setCurrentRequest(request);
setIsSheetInitialized(false); // Reset initialization state
}, []);
// Register the callback with the service on mount, unregister on unmount
useEffect(() => {
// Update log message in PurchasesService.ts to reflect A0PaymentProvider if desired
registerStripePresenter({
requestPresentation: handlePresentationRequest,
});
return () => {
registerStripePresenter(null);
};
}, [handlePresentationRequest]);
// Effect to initialize the Payment Sheet when a request arrives
useEffect(() => {
if (!currentRequest || isSheetInitialized) {
return;
}
const initialize = async () => {
// Update log messages
const incomingPublishableKey = currentRequest.params
.publishableKey;
// await initStripe({
// stripeAccountId: (currentRequest.params as any).stripeAccountId,
// publishableKey: incomingPublishableKey,
// });
const { error } = await initPaymentSheet({
customerEphemeralKeySecret: currentRequest.params.ephemeralKey,
merchantDisplayName: "A0",
paymentIntentClientSecret: currentRequest.params.paymentIntent,
setupIntentClientSecret: incomingPublishableKey,
appearance: {},
// customerId: currentRequest.params.customer,
// customerEphemeralKeySecret: currentRequest.params.ephemeralKey,
// returnURL: 'yourappscheme://stripe-redirect', // Optional: for specific redirect flows
// defaultBillingDetails: { ... } // Optional
});
if (error) {
// Update log messages
console.error("[A0PaymentProvider] Error initializing Payment Sheet:", error);
currentRequest.reject(createLibraryError(`Payment Sheet initialization failed: ${error.message}`, PURCHASES_ERROR_CODE.NETWORK_ERROR, // Or map Stripe errors
error));
setCurrentRequest(null); // Clear the request on failure
}
else {
setIsSheetInitialized(true); // Mark as initialized to trigger presentation
}
};
initialize();
}, [currentRequest, isSheetInitialized, initPaymentSheet]);
// Effect to present the Payment Sheet once initialized
useEffect(() => {
if (!isSheetInitialized || !currentRequest) {
return;
}
const present = async () => {
const { error } = await presentPaymentSheet();
if (error) {
// Update log messages
console.log("[A0PaymentProvider] Payment Sheet presentation error or cancelled:", error);
const userCancelled = error.code === PaymentSheetError.Canceled; // Corrected Canceled spelling
currentRequest.reject(createLibraryError(userCancelled
? "Payment cancelled by user."
: `Payment failed: ${error.message}`, userCancelled
? PURCHASES_ERROR_CODE.PURCHASE_CANCELLED_ERROR
: PURCHASES_ERROR_CODE.PURCHASE_INVALID_ERROR, // Map Stripe errors better if needed
error, userCancelled));
}
else {
// IMPORTANT: Server-side verification via webhooks is still crucial here!
currentRequest.resolve({ completed: true });
}
// Clear the request and state regardless of outcome
setCurrentRequest(null);
setIsSheetInitialized(false);
};
present();
}, [isSheetInitialized, currentRequest, presentPaymentSheet]);
// This component does not render anything visual itself
return null;
};
//# sourceMappingURL=A0PaymentProvider.js.map