react-native-purchases-ui
Version:
React Native in-app purchases and subscriptions made easy. Supports iOS and Android.
441 lines (428 loc) • 21.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "PAYWALL_RESULT", {
enumerable: true,
get: function () {
return _purchasesTypescriptInternal.PAYWALL_RESULT;
}
});
exports.default = void 0;
var _reactNative = require("react-native");
var _purchasesTypescriptInternal = require("@revenuecat/purchases-typescript-internal");
var _react = _interopRequireWildcard(require("react"));
var _environment = require("./utils/environment");
var _nativeModules = require("./preview/nativeModules");
var _previewComponents = require("./preview/previewComponents");
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
const LINKING_ERROR = `The package 'react-native-purchases-ui' doesn't seem to be linked. Make sure: \n\n` + '- You have run \'pod install\'\n' + '- You rebuilt the app after installing the package\n';
// Get the native module or use the preview implementation
const usingPreviewAPIMode = (0, _environment.shouldUsePreviewAPIMode)();
const RNPaywalls = usingPreviewAPIMode ? _nativeModules.previewNativeModuleRNPaywalls : _reactNative.NativeModules.RNPaywalls;
const RNCustomerCenter = usingPreviewAPIMode ? _nativeModules.previewNativeModuleRNCustomerCenter : _reactNative.NativeModules.RNCustomerCenter;
if (!RNPaywalls) {
throw new Error(LINKING_ERROR);
}
if (!RNCustomerCenter) {
throw new Error(LINKING_ERROR);
}
const NativePaywall = !usingPreviewAPIMode && _reactNative.UIManager.getViewManagerConfig('Paywall') != null ? (0, _reactNative.requireNativeComponent)('Paywall') : null;
const NativePaywallFooter = !usingPreviewAPIMode && _reactNative.UIManager.getViewManagerConfig('Paywall') != null ? (0, _reactNative.requireNativeComponent)('RCPaywallFooterView') : null;
const eventEmitter = usingPreviewAPIMode ? null : new _reactNative.NativeEventEmitter(RNPaywalls);
const customerCenterEventEmitter = usingPreviewAPIMode ? null : new _reactNative.NativeEventEmitter(RNCustomerCenter);
const InternalPaywall = ({
style,
children,
options,
onPurchaseStarted,
onPurchaseCompleted,
onPurchaseError,
onPurchaseCancelled,
onRestoreStarted,
onRestoreCompleted,
onRestoreError,
onDismiss
}) => {
if (usingPreviewAPIMode) {
return /*#__PURE__*/_react.default.createElement(_previewComponents.PreviewPaywall, {
offering: options === null || options === void 0 ? void 0 : options.offering,
displayCloseButton: options === null || options === void 0 ? void 0 : options.displayCloseButton,
fontFamily: options === null || options === void 0 ? void 0 : options.fontFamily,
onPurchaseStarted: onPurchaseStarted,
onPurchaseCompleted: onPurchaseCompleted,
onPurchaseError: onPurchaseError,
onPurchaseCancelled: onPurchaseCancelled,
onRestoreStarted: onRestoreStarted,
onRestoreCompleted: onRestoreCompleted,
onRestoreError: onRestoreError,
onDismiss: onDismiss
});
} else if (!!NativePaywall) {
return /*#__PURE__*/_react.default.createElement(NativePaywall, {
style: style,
children: children,
options: options,
onPurchaseStarted: event => onPurchaseStarted && onPurchaseStarted(event.nativeEvent),
onPurchaseCompleted: event => onPurchaseCompleted && onPurchaseCompleted(event.nativeEvent),
onPurchaseError: event => onPurchaseError && onPurchaseError(event.nativeEvent),
onPurchaseCancelled: () => onPurchaseCancelled && onPurchaseCancelled(),
onRestoreStarted: () => onRestoreStarted && onRestoreStarted(),
onRestoreCompleted: event => onRestoreCompleted && onRestoreCompleted(event.nativeEvent),
onRestoreError: event => onRestoreError && onRestoreError(event.nativeEvent),
onDismiss: () => onDismiss && onDismiss()
});
}
throw new Error(LINKING_ERROR);
};
const InternalPaywallFooterView = ({
style,
children,
options,
onPurchaseStarted,
onPurchaseCompleted,
onPurchaseError,
onPurchaseCancelled,
onRestoreStarted,
onRestoreCompleted,
onRestoreError,
onDismiss,
onMeasure
}) => {
if (usingPreviewAPIMode) {
return /*#__PURE__*/_react.default.createElement(_previewComponents.PreviewPaywall, {
offering: options === null || options === void 0 ? void 0 : options.offering,
displayCloseButton: true,
fontFamily: options === null || options === void 0 ? void 0 : options.fontFamily,
onPurchaseStarted: onPurchaseStarted,
onPurchaseCompleted: onPurchaseCompleted,
onPurchaseError: onPurchaseError,
onPurchaseCancelled: onPurchaseCancelled,
onRestoreStarted: onRestoreStarted,
onRestoreCompleted: onRestoreCompleted,
onRestoreError: onRestoreError,
onDismiss: onDismiss
});
} else if (!!NativePaywallFooter) {
return /*#__PURE__*/_react.default.createElement(NativePaywallFooter, {
style: style,
children: children,
options: options,
onPurchaseStarted: event => onPurchaseStarted && onPurchaseStarted(event.nativeEvent),
onPurchaseCompleted: event => onPurchaseCompleted && onPurchaseCompleted(event.nativeEvent),
onPurchaseError: event => onPurchaseError && onPurchaseError(event.nativeEvent),
onPurchaseCancelled: () => onPurchaseCancelled && onPurchaseCancelled(),
onRestoreStarted: () => onRestoreStarted && onRestoreStarted(),
onRestoreCompleted: event => onRestoreCompleted && onRestoreCompleted(event.nativeEvent),
onRestoreError: event => onRestoreError && onRestoreError(event.nativeEvent),
onDismiss: () => onDismiss && onDismiss(),
onMeasure: onMeasure
});
}
throw new Error(LINKING_ERROR);
};
// Currently the same as the base type, but can be extended later if needed
const InternalCustomerCenterView = !usingPreviewAPIMode && _reactNative.UIManager.getViewManagerConfig('CustomerCenterView') != null ? (0, _reactNative.requireNativeComponent)('CustomerCenterView') : null;
// This is to prevent breaking changes when the native SDK adds new options
class RevenueCatUI {
static Defaults = {
PRESENT_PAYWALL_DISPLAY_CLOSE_BUTTON: true
};
/**
* The result of presenting a paywall. This will be the last situation the user experienced before the paywall closed.
* @readonly
* @enum {string}
*/
static PAYWALL_RESULT = _purchasesTypescriptInternal.PAYWALL_RESULT;
/**
* Presents a paywall to the user with optional customization.
*
* This method allows for presenting a specific offering's paywall to the user. The caller
* can decide whether to display a close button on the paywall through the `displayCloseButton`
* parameter. By default, the close button is displayed.
*
* @param {PresentPaywallParams} params - The options for presenting the paywall.
* @returns {Promise<PAYWALL_RESULT>} A promise that resolves with the result of the paywall presentation.
*/
static presentPaywall({
offering,
displayCloseButton = RevenueCatUI.Defaults.PRESENT_PAYWALL_DISPLAY_CLOSE_BUTTON,
fontFamily
} = {}) {
var _offering$availablePa;
RevenueCatUI.logWarningIfPreviewAPIMode("presentPaywall");
return RNPaywalls.presentPaywall((offering === null || offering === void 0 ? void 0 : offering.identifier) ?? null, offering === null || offering === void 0 || (_offering$availablePa = offering.availablePackages) === null || _offering$availablePa === void 0 || (_offering$availablePa = _offering$availablePa[0]) === null || _offering$availablePa === void 0 ? void 0 : _offering$availablePa.presentedOfferingContext, displayCloseButton, fontFamily);
}
/**
* Presents a paywall to the user if a specific entitlement is not already owned.
*
* This method evaluates whether the user already owns the specified entitlement.
* If the entitlement is not owned, it presents a paywall for the specified offering (if provided), or the
* default offering (if no offering is provided), to the user. The paywall will be presented
* allowing the user the opportunity to purchase the offering. The caller
* can decide whether to display a close button on the paywall through the `displayCloseButton`
* parameter. By default, the close button is displayed.
*
* @param {PresentPaywallIfNeededParams} params - The parameters for presenting the paywall.
* @returns {Promise<PAYWALL_RESULT>} A promise that resolves with the result of the paywall presentation.
*/
static presentPaywallIfNeeded({
requiredEntitlementIdentifier,
offering,
displayCloseButton = RevenueCatUI.Defaults.PRESENT_PAYWALL_DISPLAY_CLOSE_BUTTON,
fontFamily
}) {
var _offering$availablePa2;
RevenueCatUI.logWarningIfPreviewAPIMode("presentPaywallIfNeeded");
return RNPaywalls.presentPaywallIfNeeded(requiredEntitlementIdentifier, (offering === null || offering === void 0 ? void 0 : offering.identifier) ?? null, offering === null || offering === void 0 || (_offering$availablePa2 = offering.availablePackages) === null || _offering$availablePa2 === void 0 || (_offering$availablePa2 = _offering$availablePa2[0]) === null || _offering$availablePa2 === void 0 ? void 0 : _offering$availablePa2.presentedOfferingContext, displayCloseButton, fontFamily);
}
static Paywall = ({
style,
children,
options,
onPurchaseStarted,
onPurchaseCompleted,
onPurchaseError,
onPurchaseCancelled,
onRestoreStarted,
onRestoreCompleted,
onRestoreError,
onDismiss
}) => {
return /*#__PURE__*/_react.default.createElement(InternalPaywall, {
options: options,
children: children,
onPurchaseStarted: onPurchaseStarted,
onPurchaseCompleted: onPurchaseCompleted,
onPurchaseError: onPurchaseError,
onPurchaseCancelled: onPurchaseCancelled,
onRestoreStarted: onRestoreStarted,
onRestoreCompleted: onRestoreCompleted,
onRestoreError: onRestoreError,
onDismiss: onDismiss,
style: [{
flex: 1
}, style]
});
};
static OriginalTemplatePaywallFooterContainerView = ({
style,
children,
options,
onPurchaseStarted,
onPurchaseCompleted,
onPurchaseError,
onPurchaseCancelled,
onRestoreStarted,
onRestoreCompleted,
onRestoreError,
onDismiss
}) => {
// We use 20 as the default paddingBottom because that's the corner radius in the Android native SDK.
// We also listen to safeAreaInsetsDidChange which is only sent from iOS and which is triggered when the
// safe area insets change. Not adding this extra padding on iOS will cause the content of the scrollview
// to be hidden behind the rounded corners of the paywall.
const [paddingBottom, setPaddingBottom] = (0, _react.useState)(20);
const [height, setHeight] = (0, _react.useState)(0);
(0, _react.useEffect)(() => {
const handleSafeAreaInsetsChange = ({
bottom
}) => {
setPaddingBottom(20 + bottom);
};
const subscription = eventEmitter === null || eventEmitter === void 0 ? void 0 : eventEmitter.addListener('safeAreaInsetsDidChange', handleSafeAreaInsetsChange);
return () => {
subscription === null || subscription === void 0 || subscription.remove();
};
}, []);
return /*#__PURE__*/_react.default.createElement(_reactNative.View, {
style: [{
flex: 1
}, style]
}, /*#__PURE__*/_react.default.createElement(_reactNative.ScrollView, {
contentContainerStyle: {
flexGrow: 1,
paddingBottom
}
}, children), /*#__PURE__*/_react.default.createElement(InternalPaywallFooterView, {
style: _reactNative.Platform.select({
ios: {
marginTop: -20
},
android: {
marginTop: -20,
height
}
}),
options: options,
onPurchaseStarted: onPurchaseStarted,
onPurchaseCompleted: onPurchaseCompleted,
onPurchaseError: onPurchaseError,
onPurchaseCancelled: onPurchaseCancelled,
onRestoreStarted: onRestoreStarted,
onRestoreCompleted: onRestoreCompleted,
onRestoreError: onRestoreError,
onDismiss: onDismiss,
onMeasure: event => setHeight(event.nativeEvent.measurements.height)
}));
};
/**
* A React component for embedding the Customer Center directly in your UI.
*
* This component renders the RevenueCat Customer Center as a native view that can be
* embedded within your existing React Native screens. Unlike `presentCustomerCenter()`,
* which presents the Customer Center modally, this component gives you full control
* over layout and presentation.
*
* The Customer Center allows users to manage their subscriptions, view purchase history,
* request refunds (iOS only), and access support options - all configured through the
* RevenueCat dashboard.
*
* @param style - Optional style prop to customize the appearance and layout
* @param onDismiss - Callback fired when the user dismisses the Customer Center (e.g., taps a close button)
*
* @example
* ```tsx
* import RevenueCatUI from 'react-native-purchases-ui';
*
* function MyScreen() {
* return (
* <View style={{ flex: 1 }}>
* <RevenueCatUI.CustomerCenterView
* style={{ flex: 1 }}
* onDismiss={() => navigation.goBack()}
* />
* </View>
* );
* }
* ```
*/
static CustomerCenterView = ({
style,
onDismiss,
onCustomActionSelected,
onFeedbackSurveyCompleted,
onShowingManageSubscriptions,
onRestoreCompleted,
onRestoreFailed,
onRestoreStarted,
onRefundRequestStarted,
onRefundRequestCompleted,
onManagementOptionSelected,
shouldShowCloseButton = true
}) => {
if (usingPreviewAPIMode) {
return /*#__PURE__*/_react.default.createElement(_previewComponents.PreviewCustomerCenter, {
onDismiss: () => onDismiss && onDismiss(),
style: [{
flex: 1
}, style]
});
}
if (!InternalCustomerCenterView) {
throw new Error(LINKING_ERROR);
}
return /*#__PURE__*/_react.default.createElement(InternalCustomerCenterView, {
onDismiss: onDismiss ? () => onDismiss() : undefined,
onCustomActionSelected: onCustomActionSelected ? event => onCustomActionSelected(event.nativeEvent) : undefined,
onFeedbackSurveyCompleted: onFeedbackSurveyCompleted ? event => onFeedbackSurveyCompleted(event.nativeEvent) : undefined,
onShowingManageSubscriptions: onShowingManageSubscriptions ? () => onShowingManageSubscriptions() : undefined,
onRestoreCompleted: onRestoreCompleted ? event => onRestoreCompleted(event.nativeEvent) : undefined,
onRestoreFailed: onRestoreFailed ? event => onRestoreFailed(event.nativeEvent) : undefined,
onRestoreStarted: onRestoreStarted ? () => onRestoreStarted() : undefined,
onRefundRequestStarted: onRefundRequestStarted ? event => onRefundRequestStarted(event.nativeEvent) : undefined,
onRefundRequestCompleted: onRefundRequestCompleted ? event => onRefundRequestCompleted(event.nativeEvent) : undefined,
onManagementOptionSelected: onManagementOptionSelected ? event => onManagementOptionSelected(event.nativeEvent) : undefined,
shouldShowCloseButton: shouldShowCloseButton,
style: [{
flex: 1
}, style]
});
};
/**
* Presents the customer center to the user.
*
* @param {PresentCustomerCenterParams} params - Optional parameters for presenting the customer center.
* @returns {Promise<void>} A promise that resolves when the customer center is presented.
*/
static presentCustomerCenter(params) {
if (params !== null && params !== void 0 && params.callbacks) {
const subscriptions = [];
const callbacks = params.callbacks;
if (callbacks.onFeedbackSurveyCompleted) {
const subscription = customerCenterEventEmitter === null || customerCenterEventEmitter === void 0 ? void 0 : customerCenterEventEmitter.addListener('onFeedbackSurveyCompleted', event => callbacks.onFeedbackSurveyCompleted && callbacks.onFeedbackSurveyCompleted(event));
if (subscription) {
subscriptions.push(subscription);
}
}
if (callbacks.onShowingManageSubscriptions) {
const subscription = customerCenterEventEmitter === null || customerCenterEventEmitter === void 0 ? void 0 : customerCenterEventEmitter.addListener('onShowingManageSubscriptions', () => callbacks.onShowingManageSubscriptions && callbacks.onShowingManageSubscriptions());
if (subscription) {
subscriptions.push(subscription);
}
}
if (callbacks.onRestoreCompleted) {
const subscription = customerCenterEventEmitter === null || customerCenterEventEmitter === void 0 ? void 0 : customerCenterEventEmitter.addListener('onRestoreCompleted', event => callbacks.onRestoreCompleted && callbacks.onRestoreCompleted(event));
if (subscription) {
subscriptions.push(subscription);
}
}
if (callbacks.onRestoreFailed) {
const subscription = customerCenterEventEmitter === null || customerCenterEventEmitter === void 0 ? void 0 : customerCenterEventEmitter.addListener('onRestoreFailed', event => callbacks.onRestoreFailed && callbacks.onRestoreFailed(event));
if (subscription) {
subscriptions.push(subscription);
}
}
if (callbacks.onRestoreStarted) {
const subscription = customerCenterEventEmitter === null || customerCenterEventEmitter === void 0 ? void 0 : customerCenterEventEmitter.addListener('onRestoreStarted', () => callbacks.onRestoreStarted && callbacks.onRestoreStarted());
if (subscription) {
subscriptions.push(subscription);
}
}
if (callbacks.onRefundRequestStarted) {
const subscription = customerCenterEventEmitter === null || customerCenterEventEmitter === void 0 ? void 0 : customerCenterEventEmitter.addListener('onRefundRequestStarted', event => callbacks.onRefundRequestStarted && callbacks.onRefundRequestStarted(event));
if (subscription) {
subscriptions.push(subscription);
}
}
if (callbacks.onRefundRequestCompleted) {
const subscription = customerCenterEventEmitter === null || customerCenterEventEmitter === void 0 ? void 0 : customerCenterEventEmitter.addListener('onRefundRequestCompleted', event => callbacks.onRefundRequestCompleted && callbacks.onRefundRequestCompleted(event));
if (subscription) {
subscriptions.push(subscription);
}
}
if (callbacks.onManagementOptionSelected) {
const subscription = customerCenterEventEmitter === null || customerCenterEventEmitter === void 0 ? void 0 : customerCenterEventEmitter.addListener('onManagementOptionSelected', event => callbacks.onManagementOptionSelected && callbacks.onManagementOptionSelected(event));
if (subscription) {
subscriptions.push(subscription);
}
}
if (callbacks.onCustomActionSelected) {
const subscription = customerCenterEventEmitter === null || customerCenterEventEmitter === void 0 ? void 0 : customerCenterEventEmitter.addListener('onCustomActionSelected', event => callbacks.onCustomActionSelected && callbacks.onCustomActionSelected(event));
if (subscription) {
subscriptions.push(subscription);
}
}
// Return a promise that resolves when the customer center is dismissed
return RNCustomerCenter.presentCustomerCenter().finally(() => {
// Clean up all event listeners when the customer center is dismissed
subscriptions.forEach(subscription => subscription.remove());
});
}
RevenueCatUI.logWarningIfPreviewAPIMode("presentCustomerCenter");
return RNCustomerCenter.presentCustomerCenter();
}
/**
* @deprecated, Use {@link OriginalTemplatePaywallFooterContainerView} instead
*/
static PaywallFooterContainerView = RevenueCatUI.OriginalTemplatePaywallFooterContainerView;
static logWarningIfPreviewAPIMode(methodName) {
if (usingPreviewAPIMode) {
// tslint:disable-next-line:no-console
console.warn(`[RevenueCatUI] [${methodName}] This method is available but has no effect in Preview API mode.`);
}
}
}
exports.default = RevenueCatUI;
//# sourceMappingURL=index.js.map