react-native-purchases icon indicating copy to clipboard operation
react-native-purchases copied to clipboard

[Customer Center] `presentCustomerCenter()` does not work inside react-navigation modal

Open rrebase opened this issue 11 months ago • 6 comments

  1. Environment
    1. Platform: iOS
    2. SDK version:
      • "react-native-purchases": "8.7.0"
      • "react-native-purchases-ui": "8.7.0"
    3. React Native version: 0.76
    4. Related deps
      • "@react-navigation/native": "7.0.14"
      • "@react-navigation/native-stack": "7.2.0"
      • "react-native-screens": "4.4.0"
  2. Steps to reproduce, with a description of expected vs. actual behavior

Try to open customer center from a modal screen via RevenueCatUI.presentCustomerCenter()

Expected: Customer Center opens Actual: Nothing happens

Works as expected on non-modal screens.

rrebase avatar Mar 03 '25 20:03 rrebase

👀 We've just linked this issue to our internal tracker and notified the team. Thank you for reporting, we're checking this out!

RCGitBot avatar Mar 03 '25 20:03 RCGitBot

Thank you for opening, we'll take a look. Do you get any logs? Debug logs would be very helpful in order to debug this

vegaro avatar Mar 04 '25 14:03 vegaro

@vegaro logs:

[UIKitCore] Attempt to present <PurchasesHybridCommonUI.CustomerCenterUIViewController: 0x10670b320> on
<UIViewController: 0x102a247d0> (from <UIViewController: 0x102a247d0>) which is already presenting <RNSScreen:
0x1269ee200>.

rrebase avatar Mar 04 '25 17:03 rrebase

Created a quick reproducable for you

bun create expo
bun add react-native-purchases react-native-purchases-ui
// Added modal & button that calls `presentCustomerCenter()`

Here https://github.com/rrebase/rc-customer-center-bug-demo

rrebase avatar Mar 04 '25 17:03 rrebase

@rrebase just opened https://github.com/RevenueCat/react-native-purchases/pull/1209

facumenzella avatar Mar 11 '25 11:03 facumenzella

it doesn't work with wix/react-native-navigation as well.

tarouboy avatar Jun 03 '25 15:06 tarouboy

Any update on this?

nathancovey avatar Jul 09 '25 01:07 nathancovey

I am also posting here to say this is an issue for us. I can't get it to show at all in a modal, on a dashboard etc.

It would also be nice to have a JSX component for this like the paywall as its odd to have a promise to display a UI element.

HilSny avatar Jul 15 '25 17:07 HilSny

Here's a native log if that helps address the issue

Attempt to present <PurchasesHybridCommonUI.CustomerCenterUIViewController: 0x1599098a0> on <UIViewController: 0x101623f10> (from <UIViewController: 0x101623f10>) which is already presenting <RCTModalHostViewController: 0x168bb4600>.

HilSny avatar Jul 15 '25 17:07 HilSny

+1

alextbogdanov avatar Sep 16 '25 10:09 alextbogdanov

@alextbogdanov can you share the code you're using?

facumenzella avatar Sep 16 '25 10:09 facumenzella

@facumenzella I'm just doing the following:

import RevenueCatUI from "react-native-purchases-ui";

          <TouchableOpacity
            className="mx-4 p-4 bg-white rounded-xl shadow-sm shadow-gray-200 mt-6 flex-row items-center justify-between gap-x-2"
            onPress={async () => {
              await RevenueCatUI.presentCustomerCenter();
            }}
          >

...

The problem is that the screen I'm calling it from is a modal. If I make it a basic screen it works:


        <Stack.Screen
          name="my-profile"
          options={{
            presentation: "modal",
            gestureEnabled: false,
          }}
        />

alextbogdanov avatar Sep 16 '25 14:09 alextbogdanov

Thanks for raising this. We added flexible presentation options in PR #1209. await RevenueCatUI.presentCustomerCenter() is expected not to work inside another modal — use the view directly instead.

Full-Screen Screen (React Navigation)

  // CustomerCenterScreen.tsx
  import React from 'react';
  import RevenueCatUI from 'react-native-purchases-ui';

  export default function CustomerCenterScreen() {
    return (
      <RevenueCatUI.CustomerCenterView
        style={{ flex: 1 }}
        // Hide internal close button; rely on nav back
        shouldShowCloseButton={false}
        onCustomActionSelected={({ actionId }) => {
          // Handle custom actions if configured in the dashboard
          console.log('Custom action:', actionId);
        }}
      />
    );
  }

  // In your navigator
  <Stack.Screen
    name="CustomerCenter"
    component={CustomerCenterScreen}
    options={{ title: 'Customer Center' }}
  />

Modal Without Header (Use Internal Close)

  // CustomerCenterModal.tsx
  import React from 'react';
  import RevenueCatUI from 'react-native-purchases-ui';

  export default function CustomerCenterModal({ navigation }) {
    return (
      <RevenueCatUI.CustomerCenterView
        style={{ flex: 1 }}
        onDismiss={() => navigation.goBack()}
        onCustomActionSelected={({ actionId }) => {
          console.log('Custom action:', actionId);
        }}
      />
    );
  }

  // In your navigator
  <Stack.Group screenOptions={{ presentation: 'modal', headerShown: false }}>
    <Stack.Screen name="CustomerCenterModal" component={CustomerCenterModal} />
  </Stack.Group>

Modal With Header (Use System Back)

  // CustomerCenterModalWithHeader.tsx
  import React from 'react';
  import RevenueCatUI from 'react-native-purchases-ui';

  export default function CustomerCenterModalWithHeader() {
    return (
      <RevenueCatUI.CustomerCenterView
        style={{ flex: 1 }}
        // Hide internal close button; header back will dismiss
        shouldShowCloseButton={false}
      />
    );
  }

  // In your navigator
  <Stack.Group screenOptions={{ presentation: 'modal', headerShown: true }}>
    <Stack.Screen
      name="CustomerCenterModalWithHeader"
      component={CustomerCenterModalWithHeader}
    />
  </Stack.Group>

Plain React Native Modal

  import React from 'react';
  import { Modal, View } from 'react-native';
  import RevenueCatUI from 'react-native-purchases-ui';

  export default function CustomerCenterRNModal({
    visible,
    onRequestClose,
  }: {
    visible: boolean;
    onRequestClose: () => void;
  }) {
    return (
      <Modal visible={visible} animationType="slide" onRequestClose={onRequestClose}>
        <View style={{ flex: 1 }}>
          <RevenueCatUI.CustomerCenterView
            style={{ flex: 1 }}
            shouldShowCloseButton={true}
            onDismiss={onRequestClose}
          />
        </View>
      </Modal>
    );
  }

Notes

  • Use shouldShowCloseButton={false} when you don't want an internal close UI;
  • iOS 15+ is required for Customer Center.

facumenzella avatar Sep 16 '25 15:09 facumenzella

@alextbogdanov please let me know if that doesn't work for you. Otherwise, I'll close this one to avoid confusion :)

facumenzella avatar Sep 16 '25 15:09 facumenzella