Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ To enable verbose logging, set the `DEBUG` (or `EXPO_PUBLIC_DEBUG` for mobile) v

* Everything: `EXPO_PUBLIC_DEBUG=*` (extremely noisy!)
* App: `EXPO_PUBLIC_DEBUG=app:*`
* RevenueCat: `EXPO_PUBLIC_DEBUG=revenuecat:*`

## Deploying

Expand Down
214 changes: 214 additions & 0 deletions REVENUECAT_SETUP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
# RevenueCat Integration Setup Guide

## Overview

RevenueCat SDK has been successfully integrated into your Plannting mobile app. This guide will help you complete the setup and configure your products.

## Installation

The packages have been added to `package.json`. You need to install them:

```bash
cd apps/mobile
npm install
# or
npx expo install react-native-purchases react-native-purchases-ui
```

## Configuration

### 1. API Key

The API key is already configured in `apps/mobile/src/config/index.ts`:
- Test API Key: `test_jNLGmFtxUPIzgIsTensvdythpeN`
- For production, set `EXPO_PUBLIC_REVENUECAT_API_KEY` environment variable

### 2. RevenueCat Dashboard Setup

1. **Create Products in App Store Connect / Google Play Console:**
- Monthly subscription: `monthly`
- Yearly subscription: `yearly`
- Lifetime purchase: `lifetime`

2. **Configure in RevenueCat Dashboard:**
- Go to your RevenueCat project
- Navigate to Products
- Add your products with the identifiers: `monthly`, `yearly`, `lifetime`
- Create an entitlement: `Plannting Pro`
- Attach all three products to the `Plannting Pro` entitlement

3. **Create an Offering:**
- Go to Offerings in RevenueCat dashboard
- Create a new offering (e.g., "Default")
- Add your packages (monthly, yearly, lifetime)
- Set one as the default offering

## Features Implemented

### ✅ Core Functionality
- RevenueCat SDK initialization with API key
- User identification and login/logout
- Customer info retrieval
- Entitlement checking for "Plannting Pro"
- Purchase flow with error handling
- Restore purchases functionality

### ✅ UI Components
- **Paywall Component** (`src/components/Paywall.tsx`)
- Native RevenueCat Paywall UI support
- Custom paywall fallback
- Package selection (Monthly, Yearly, Lifetime)
- Purchase handling with loading states
- Restore purchases button

- **Customer Center Component** (`src/components/CustomerCenter.tsx`)
- Native RevenueCat Customer Info View
- Subscription status display
- Subscription details
- Restore purchases functionality

### ✅ Integration
- RevenueCat Context Provider integrated into app layout
- Settings screen updated with subscription management
- Automatic initialization when user logs in
- Automatic cleanup when user logs out

## File Structure

```
apps/mobile/src/
├── services/
│ └── revenueCat/
│ └── index.ts # RevenueCat service functions
├── contexts/
│ └── RevenueCatContext.tsx # RevenueCat context provider
├── hooks/
│ └── useRevenueCat.ts # Custom hooks for RevenueCat
├── components/
│ ├── Paywall.tsx # Paywall component
│ └── CustomerCenter.tsx # Customer Center component
└── config/
├── index.ts # Configuration (includes API key)
└── types.ts # Type definitions
```

## Usage Examples

### Check if User Has Pro
```typescript
import { useIsPro } from '../hooks/useRevenueCat'

function MyComponent() {
const { isPro, isLoading } = useIsPro()

if (isLoading) return <Loading />
if (isPro) return <ProFeatures />
return <UpgradePrompt />
}
```

### Show Paywall
```typescript
import { Paywall } from '../components/Paywall'

function MyComponent() {
const [showPaywall, setShowPaywall] = useState(false)

return (
<>
<Button onPress={() => setShowPaywall(true)}>Upgrade</Button>
<Paywall
visible={showPaywall}
onClose={() => setShowPaywall(false)}
onPurchaseComplete={() => {
console.log('Purchase completed!')
}}
/>
</>
)
}
```

### Access Customer Info
```typescript
import { useCustomerInfo } from '../hooks/useRevenueCat'

function MyComponent() {
const { customerInfo, isLoading, refreshCustomerInfo } = useCustomerInfo()

// Access customer info
console.log(customerInfo?.entitlements.active)
}
```

## Testing

### Sandbox Testing
1. Use test API key (already configured)
2. Create sandbox test accounts in App Store Connect / Google Play Console
3. Test purchases in development builds
4. Verify entitlement status updates correctly

### Production Checklist
- [ ] Replace test API key with production key
- [ ] Configure products in App Store Connect / Google Play Console
- [ ] Set up products and entitlements in RevenueCat dashboard
- [ ] Create and configure offering in RevenueCat
- [ ] Test end-to-end purchase flow
- [ ] Test restore purchases
- [ ] Test subscription renewal
- [ ] Test cancellation flow

## Product Identifiers

The app expects these product identifiers:
- `monthly` - Monthly subscription
- `yearly` - Yearly subscription
- `lifetime` - Lifetime purchase

## Entitlement Identifier

- `Plannting Pro` - Main entitlement that grants access to premium features

## Best Practices

1. **Error Handling**: All purchase operations include comprehensive error handling
2. **Loading States**: UI shows loading indicators during async operations
3. **User Feedback**: Alerts inform users of success/failure
4. **Automatic Refresh**: Customer info refreshes after purchases
5. **User Identification**: RevenueCat automatically links purchases to user IDs

## Troubleshooting

### Common Issues

1. **"No packages available"**
- Check that products are configured in RevenueCat dashboard
- Verify offering is set as default
- Ensure products are attached to entitlement

2. **Purchases not restoring**
- Verify user is logged in with same account
- Check RevenueCat dashboard for purchase records
- Ensure restore is called after user login

3. **Entitlement not active**
- Check product configuration in RevenueCat
- Verify subscription status in App Store/Play Store
- Check expiration dates in customer info

## Next Steps

1. Install the npm packages
2. Configure products in RevenueCat dashboard
3. Test the integration in development
4. Set up production API key
5. Deploy and test in production

## Support

For RevenueCat-specific issues, refer to:
- [RevenueCat Documentation](https://www.revenuecat.com/docs)
- [React Native SDK Docs](https://www.revenuecat.com/docs/getting-started/installation/reactnative)
- [Paywalls Documentation](https://www.revenuecat.com/docs/tools/paywalls)
- [Customer Center Documentation](https://www.revenuecat.com/docs/tools/customer-center)
12 changes: 12 additions & 0 deletions apps/mobile/.env.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# App name for display on device home screens
APP_NAME=Plannting Dev

# Debug logging
# See readme for "Verbose debug logging"
EXPO_PUBLIC_DEBUG=revenuecat:*

# URL to API
EXPO_PUBLIC_API_BASE_URL=https://api.plannting.completecodesolutions.com

# RevenueCat
EXPO_PUBLIC_REVENUECAT_API_KEY=test_jNLGmFtxUPIzgIsTensvdythpeN
4 changes: 4 additions & 0 deletions apps/mobile/.env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Debug logging
# See readme for "Verbose debug logging"
EXPO_PUBLIC_DEBUG=app:*

# URL to API
EXPO_PUBLIC_API_BASE_URL=http://localhost:3000

# RevenueCat
EXPO_PUBLIC_REVENUECAT_API_KEY=****
2 changes: 0 additions & 2 deletions apps/mobile/.env.production

This file was deleted.

2 changes: 1 addition & 1 deletion apps/mobile/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ yarn-error.*
.DS_Store
*.pem

!.env.production
!.env.dev

# typescript
*.tsbuildinfo
Expand Down
10 changes: 7 additions & 3 deletions apps/mobile/app.config.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { version } from './package.json'

import * as dotenv from 'dotenv'

dotenv.config()

export default {
"expo": {
"name": "Plannting",
"slug": "plannting",
"name": process.env.APP_NAME || 'Plannting',
"slug": 'plannting',
"version": version.replace(/^([0-9]*\.[0-9]*\.[0-9]*).*/, '$1'),
runtimeVersion: '5',
runtimeVersion: '6',
scheme: 'plannting',
"orientation": "portrait",
"icon": "./assets/icon.png",
Expand Down
25 changes: 20 additions & 5 deletions apps/mobile/eas.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,34 @@
},
"developmentClient": false,
"autoIncrement": true,
"env": { "EXPO_PUBLIC_API_BASE_URL": "https://api.plannting.completecodesolutions.com" }
"env": {
"EXPO_PUBLIC_API_BASE_URL": "https://api.plannting.completecodesolutions.com",
"EXPO_PUBLIC_REVENUECAT_API_KEY": "****"
}
},
"uat": {
"extends": "production",
"env": {
"EXPO_PUBLIC_API_BASE_URL": "https://api.plannting.completecodesolutions.com",
"EXPO_PUBLIC_REVENUECAT_API_KEY": "test_jNLGmFtxUPIzgIsTensvdythpeN"
}
},
"on-demand": {
"dev": {
"extends": "production",
"developmentClient": true,
"distribution": "internal",
"env": { "EXPO_PUBLIC_API_BASE_URL": "https://api.plannting.completecodesolutions.com" }
"distribution": "internal"
}
},
"submit": {
"production": {
"ios": {
"ascAppId": "abc123",
"ascAppId": "6756863931",
"appleTeamId": "X6H3QV6VCE"
}
},
"uat": {
"ios": {
"ascAppId": "6756863931",
"appleTeamId": "X6H3QV6VCE"
}
}
Expand Down
7 changes: 5 additions & 2 deletions apps/mobile/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
"lint": "eslint src --ext .ts",
"build:development:add-device": "eas device:create",
"build:development:list-devices": "eas device:list",
"build:development:build": "eas build --clear-cache --platform ios --profile on-demand --no-wait",
"build:development:update": "ts-node ../../scripts/updateDevelopmentBuild.ts"
"build:development:build": "eas build --clear-cache --platform ios --profile dev --no-wait",
"build:development:update": "ts-node ../../scripts/updateDevelopmentBuild.ts",
"build:uat": "eas build --profile uat --platform ios --auto-submit --no-wait"
},
"dependencies": {
"@react-native-async-storage/async-storage": "^2.2.0",
Expand All @@ -35,6 +36,8 @@
"react": "19.1.0",
"react-dom": "19.1.0",
"react-native": "0.81.5",
"react-native-purchases": "^9.6.11",
"react-native-purchases-ui": "^9.6.11",
"react-native-safe-area-context": "~5.6.2",
"react-native-screens": "~4.16.0",
"superjson": "^1.13.3",
Expand Down
Loading