mixpanel-react-native 3.1.2 → 3.2.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +12 -1
- package/.github/dependabot.yml +7 -0
- package/.github/workflows/node.js.yml +24 -1
- package/.vscode/settings.json +2 -1
- package/MixpanelReactNative.podspec +1 -1
- package/Samples/MixpanelExample/ios/MixpanelExample.xcworkspace/contents.xcworkspacedata +10 -0
- package/Samples/MixpanelExample/ios/Podfile.lock +1996 -0
- package/Samples/MixpanelStarter/.bundle/config +2 -0
- package/Samples/MixpanelStarter/.env.example +4 -0
- package/Samples/MixpanelStarter/.eslintrc.js +4 -0
- package/Samples/MixpanelStarter/.prettierrc.js +5 -0
- package/Samples/MixpanelStarter/.watchmanconfig +1 -0
- package/Samples/MixpanelStarter/App.tsx +10 -0
- package/Samples/MixpanelStarter/CLAUDE.md +538 -0
- package/Samples/MixpanelStarter/Gemfile +16 -0
- package/Samples/MixpanelStarter/INTEGRATION_GUIDE.md +606 -0
- package/Samples/MixpanelStarter/README.md +406 -0
- package/Samples/MixpanelStarter/__tests__/MixpanelContext.test.tsx +63 -0
- package/Samples/MixpanelStarter/android/app/build.gradle +119 -0
- package/Samples/MixpanelStarter/android/app/debug.keystore +0 -0
- package/Samples/MixpanelStarter/android/app/proguard-rules.pro +10 -0
- package/Samples/MixpanelStarter/android/app/src/main/AndroidManifest.xml +27 -0
- package/Samples/MixpanelStarter/android/app/src/main/java/com/mixpanelstarter/MainActivity.kt +22 -0
- package/Samples/MixpanelStarter/android/app/src/main/java/com/mixpanelstarter/MainApplication.kt +27 -0
- package/Samples/MixpanelStarter/android/app/src/main/res/drawable/rn_edit_text_material.xml +37 -0
- package/Samples/MixpanelStarter/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
- package/Samples/MixpanelStarter/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
- package/Samples/MixpanelStarter/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
- package/Samples/MixpanelStarter/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
- package/Samples/MixpanelStarter/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- package/Samples/MixpanelStarter/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
- package/Samples/MixpanelStarter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- package/Samples/MixpanelStarter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- package/Samples/MixpanelStarter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- package/Samples/MixpanelStarter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
- package/Samples/MixpanelStarter/android/app/src/main/res/values/strings.xml +3 -0
- package/Samples/MixpanelStarter/android/app/src/main/res/values/styles.xml +9 -0
- package/Samples/MixpanelStarter/android/build.gradle +21 -0
- package/Samples/MixpanelStarter/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/Samples/MixpanelStarter/android/gradle/wrapper/gradle-wrapper.properties +7 -0
- package/Samples/MixpanelStarter/android/gradle.properties +44 -0
- package/Samples/MixpanelStarter/android/gradlew +251 -0
- package/Samples/MixpanelStarter/android/gradlew.bat +99 -0
- package/Samples/MixpanelStarter/android/settings.gradle +6 -0
- package/Samples/MixpanelStarter/app.json +4 -0
- package/Samples/MixpanelStarter/babel.config.js +14 -0
- package/Samples/MixpanelStarter/index.js +9 -0
- package/Samples/MixpanelStarter/ios/.xcode.env +11 -0
- package/Samples/MixpanelStarter/ios/MixpanelStarter/AppDelegate.swift +48 -0
- package/Samples/MixpanelStarter/ios/MixpanelStarter/Images.xcassets/AppIcon.appiconset/Contents.json +53 -0
- package/Samples/MixpanelStarter/ios/MixpanelStarter/Images.xcassets/Contents.json +6 -0
- package/Samples/MixpanelStarter/ios/MixpanelStarter/Info.plist +55 -0
- package/Samples/MixpanelStarter/ios/MixpanelStarter/LaunchScreen.storyboard +47 -0
- package/Samples/MixpanelStarter/ios/MixpanelStarter/PrivacyInfo.xcprivacy +38 -0
- package/Samples/MixpanelStarter/ios/MixpanelStarter.xcodeproj/project.pbxproj +482 -0
- package/Samples/MixpanelStarter/ios/MixpanelStarter.xcodeproj/xcshareddata/xcschemes/MixpanelStarter.xcscheme +88 -0
- package/Samples/MixpanelStarter/ios/MixpanelStarter.xcworkspace/contents.xcworkspacedata +10 -0
- package/Samples/MixpanelStarter/ios/Podfile +34 -0
- package/Samples/MixpanelStarter/ios/Podfile.lock +2839 -0
- package/Samples/MixpanelStarter/jest.config.js +3 -0
- package/Samples/MixpanelStarter/metro.config.js +42 -0
- package/Samples/MixpanelStarter/package-lock.json +12141 -0
- package/Samples/MixpanelStarter/package.json +51 -0
- package/Samples/MixpanelStarter/src/@types/env.d.ts +3 -0
- package/Samples/MixpanelStarter/src/App.tsx +83 -0
- package/Samples/MixpanelStarter/src/components/ActionButton.tsx +92 -0
- package/Samples/MixpanelStarter/src/components/ErrorBoundary.tsx +81 -0
- package/Samples/MixpanelStarter/src/components/EventTrackingLog.tsx +163 -0
- package/Samples/MixpanelStarter/src/components/FlagCard.tsx +199 -0
- package/Samples/MixpanelStarter/src/components/InfoCard.tsx +77 -0
- package/Samples/MixpanelStarter/src/components/TestResultDisplay.tsx +181 -0
- package/Samples/MixpanelStarter/src/constants/tracking.ts +77 -0
- package/Samples/MixpanelStarter/src/contexts/MixpanelContext.tsx +159 -0
- package/Samples/MixpanelStarter/src/screens/FeatureFlagsScreen.tsx +1011 -0
- package/Samples/MixpanelStarter/src/screens/HomeScreen.tsx +307 -0
- package/Samples/MixpanelStarter/src/screens/OnboardingScreen.tsx +253 -0
- package/Samples/MixpanelStarter/src/screens/SettingsScreen.tsx +316 -0
- package/Samples/MixpanelStarter/src/types/flags.types.ts +42 -0
- package/Samples/MixpanelStarter/src/types/mixpanel.types.ts +26 -0
- package/Samples/MixpanelStarter/tsconfig.json +13 -0
- package/__tests__/flags.test.js +730 -0
- package/__tests__/index.test.js +7 -3
- package/__tests__/jest_setup.js +18 -0
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/mixpanel/reactnative/MixpanelReactNativeModule.java +272 -2
- package/index.d.ts +64 -1
- package/index.js +42 -3
- package/ios/MixpanelReactNative.m +19 -1
- package/ios/MixpanelReactNative.swift +183 -5
- package/javascript/mixpanel-flags-js.js +463 -0
- package/javascript/mixpanel-flags.js +290 -0
- package/javascript/mixpanel-main.js +13 -1
- package/package.json +2 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
|
@@ -0,0 +1,538 @@
|
|
|
1
|
+
# CLAUDE.md - MixpanelStarter Sample App
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code when working with the MixpanelStarter sample application.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
**Purpose**: Modern, production-ready React Native sample app demonstrating Mixpanel SDK integration with TypeScript, Context API, and best practices.
|
|
8
|
+
|
|
9
|
+
**Target Audience**: Developers learning to integrate Mixpanel into their React Native apps.
|
|
10
|
+
|
|
11
|
+
**Positioning**: Bridges the gap between SimpleMixpanel (too basic) and MixpanelDemo (too complex), demonstrating 80% of common use cases.
|
|
12
|
+
|
|
13
|
+
## Quick Reference
|
|
14
|
+
|
|
15
|
+
### Tech Stack
|
|
16
|
+
- **React Native**: 0.82.1
|
|
17
|
+
- **React**: 19.1.1
|
|
18
|
+
- **TypeScript**: Strict mode enabled
|
|
19
|
+
- **Navigation**: React Navigation 7.x with bottom tabs
|
|
20
|
+
- **State Management**: Context API pattern
|
|
21
|
+
- **Testing**: Jest with React Native Testing Library
|
|
22
|
+
|
|
23
|
+
### Key Dependencies
|
|
24
|
+
- `mixpanel-react-native` - Main SDK (file:../..)
|
|
25
|
+
- `@react-native-async-storage/async-storage` - Required for Mixpanel
|
|
26
|
+
- `@react-navigation/native` + `@react-navigation/bottom-tabs` - Navigation
|
|
27
|
+
- `react-native-dotenv` - Environment variables
|
|
28
|
+
|
|
29
|
+
## Commands
|
|
30
|
+
|
|
31
|
+
### Development
|
|
32
|
+
```bash
|
|
33
|
+
# Install dependencies
|
|
34
|
+
npm install
|
|
35
|
+
cd ios && pod install && cd ..
|
|
36
|
+
|
|
37
|
+
# Run app
|
|
38
|
+
npm run ios # iOS simulator
|
|
39
|
+
npm run android # Android emulator
|
|
40
|
+
npm start # Start Metro bundler
|
|
41
|
+
|
|
42
|
+
# Testing
|
|
43
|
+
npm test # Run Jest tests
|
|
44
|
+
npm test -- --coverage # With coverage
|
|
45
|
+
npx tsc --noEmit # TypeScript compilation check
|
|
46
|
+
|
|
47
|
+
# Linting
|
|
48
|
+
npm run lint # Run ESLint
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Environment Setup
|
|
52
|
+
```bash
|
|
53
|
+
# Create environment file
|
|
54
|
+
cp .env.example .env
|
|
55
|
+
# Edit .env and set: MIXPANEL_TOKEN=your_token_here
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Troubleshooting Commands
|
|
59
|
+
```bash
|
|
60
|
+
# Clear Metro cache
|
|
61
|
+
npm start -- --reset-cache
|
|
62
|
+
|
|
63
|
+
# Clean iOS build
|
|
64
|
+
cd ios && xcodebuild clean && cd ..
|
|
65
|
+
|
|
66
|
+
# Clean Android build
|
|
67
|
+
cd android && ./gradlew clean && cd ..
|
|
68
|
+
|
|
69
|
+
# Reinstall dependencies
|
|
70
|
+
rm -rf node_modules && npm install
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Architecture & Code Patterns
|
|
74
|
+
|
|
75
|
+
### Core Architecture Pattern: Context API + Custom Hook
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
// Provider wraps app root (src/App.tsx)
|
|
79
|
+
<MixpanelProvider token={token} trackAutomaticEvents={true}>
|
|
80
|
+
<NavigationContainer>
|
|
81
|
+
{/* app content */}
|
|
82
|
+
</NavigationContainer>
|
|
83
|
+
</MixpanelProvider>
|
|
84
|
+
|
|
85
|
+
// Hook usage in any component
|
|
86
|
+
const { mixpanel, isInitialized, track, identify } = useMixpanel();
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Why Context API?**
|
|
90
|
+
- Simple, no boilerplate
|
|
91
|
+
- Built into React (widely understood)
|
|
92
|
+
- Sufficient for Mixpanel's simple state needs
|
|
93
|
+
- Avoids prop drilling
|
|
94
|
+
|
|
95
|
+
### File Naming Conventions
|
|
96
|
+
- **Components**: PascalCase (ActionButton.tsx, InfoCard.tsx)
|
|
97
|
+
- **Screens**: PascalCase with "Screen" suffix (OnboardingScreen.tsx)
|
|
98
|
+
- **Contexts**: PascalCase with "Context" suffix (MixpanelContext.tsx)
|
|
99
|
+
- **Types**: kebab-case with .types.ts suffix (mixpanel.types.ts)
|
|
100
|
+
- **Constants**: kebab-case (tracking.ts)
|
|
101
|
+
|
|
102
|
+
### Import Order Pattern
|
|
103
|
+
```typescript
|
|
104
|
+
// 1. External libraries (React, React Native)
|
|
105
|
+
import React, {useState, useEffect} from 'react';
|
|
106
|
+
import {View, Text, StyleSheet} from 'react-native';
|
|
107
|
+
|
|
108
|
+
// 2. Navigation
|
|
109
|
+
import {NavigationContainer} from '@react-navigation/native';
|
|
110
|
+
|
|
111
|
+
// 3. Internal contexts/hooks
|
|
112
|
+
import {useMixpanel} from '../contexts/MixpanelContext';
|
|
113
|
+
|
|
114
|
+
// 4. Components
|
|
115
|
+
import {ActionButton} from '../components/ActionButton';
|
|
116
|
+
|
|
117
|
+
// 5. Constants/types
|
|
118
|
+
import {Events, Properties} from '../constants/tracking';
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Event Tracking Pattern
|
|
122
|
+
```typescript
|
|
123
|
+
// Always use constants (prevents typos, enables autocomplete)
|
|
124
|
+
import {Events, Properties} from '../constants/tracking';
|
|
125
|
+
|
|
126
|
+
// Check initialization before tracking
|
|
127
|
+
if (isInitialized) {
|
|
128
|
+
track(Events.SCREEN_VIEWED, {
|
|
129
|
+
[Properties.SCREEN_NAME]: 'Home',
|
|
130
|
+
[Properties.TIMESTAMP]: new Date().toISOString(),
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Track on mount with useEffect
|
|
135
|
+
useEffect(() => {
|
|
136
|
+
if (isInitialized) {
|
|
137
|
+
track(Events.SCREEN_VIEWED, {...});
|
|
138
|
+
}
|
|
139
|
+
}, [isInitialized, track]);
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### User Identification Pattern
|
|
143
|
+
```typescript
|
|
144
|
+
// Complete signup flow (OnboardingScreen.tsx:52-90)
|
|
145
|
+
const previousId = await mixpanel.getDistinctId();
|
|
146
|
+
identify(userId); // Set new identity
|
|
147
|
+
await alias(userId, previousId); // Link anonymous events
|
|
148
|
+
mixpanel.getPeople().set({...}); // Set profile
|
|
149
|
+
mixpanel.getPeople().setOnce({...}); // Set immutable properties
|
|
150
|
+
track(Events.USER_SIGNED_UP, {...}); // Track event
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Privacy-Compliant Logout Pattern
|
|
154
|
+
```typescript
|
|
155
|
+
// SettingsScreen.tsx demonstrates GDPR-compliant logout
|
|
156
|
+
track('User Logged Out', {...}); // Track before clearing
|
|
157
|
+
await flush(); // Ensure events sent
|
|
158
|
+
reset(); // Clear all data
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Project Structure
|
|
162
|
+
|
|
163
|
+
```
|
|
164
|
+
MixpanelStarter/
|
|
165
|
+
├── src/
|
|
166
|
+
│ ├── contexts/
|
|
167
|
+
│ │ └── MixpanelContext.tsx # Context provider + useMixpanel hook
|
|
168
|
+
│ ├── screens/ # 3 tab screens
|
|
169
|
+
│ │ ├── OnboardingScreen.tsx # User identification flow
|
|
170
|
+
│ │ ├── HomeScreen.tsx # Event tracking patterns
|
|
171
|
+
│ │ └── SettingsScreen.tsx # Privacy controls
|
|
172
|
+
│ ├── components/ # Reusable components
|
|
173
|
+
│ │ ├── ErrorBoundary.tsx # Error boundary wrapper
|
|
174
|
+
│ │ ├── ActionButton.tsx # Button with loading states
|
|
175
|
+
│ │ └── InfoCard.tsx # Key-value display card
|
|
176
|
+
│ ├── types/
|
|
177
|
+
│ │ └── mixpanel.types.ts # TypeScript interfaces
|
|
178
|
+
│ ├── constants/
|
|
179
|
+
│ │ └── tracking.ts # Event names & properties
|
|
180
|
+
│ ├── @types/
|
|
181
|
+
│ │ └── env.d.ts # Environment variable types
|
|
182
|
+
│ └── App.tsx # Navigation setup
|
|
183
|
+
├── __tests__/
|
|
184
|
+
│ └── MixpanelContext.test.tsx # Context tests
|
|
185
|
+
├── ios/ # iOS native code
|
|
186
|
+
├── android/ # Android native code
|
|
187
|
+
├── .env.example # Environment template
|
|
188
|
+
├── README.md # User-facing documentation
|
|
189
|
+
└── INTEGRATION_GUIDE.md # Step-by-step integration guide
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### File Responsibilities
|
|
193
|
+
|
|
194
|
+
**MixpanelContext.tsx** (src/contexts/)
|
|
195
|
+
- Initializes Mixpanel SDK on mount
|
|
196
|
+
- Sets default super properties (app version, platform, environment)
|
|
197
|
+
- Provides convenience wrapper methods (track, identify, alias, reset, flush)
|
|
198
|
+
- Manages loading/error states
|
|
199
|
+
- Exports useMixpanel hook
|
|
200
|
+
|
|
201
|
+
**OnboardingScreen.tsx** (src/screens/)
|
|
202
|
+
- Demonstrates: identify(), alias(), getPeople().set(), setOnce()
|
|
203
|
+
- Shows anonymous-to-identified user flow
|
|
204
|
+
- Displays current distinct ID
|
|
205
|
+
- Guest mode vs signup comparison
|
|
206
|
+
|
|
207
|
+
**HomeScreen.tsx** (src/screens/)
|
|
208
|
+
- Demonstrates: track(), timeEvent(), registerSuperProperties()
|
|
209
|
+
- Event tracking with rich properties
|
|
210
|
+
- Timed events (video start/complete)
|
|
211
|
+
- Dynamic super properties (dark mode, notifications)
|
|
212
|
+
- Displays current super properties
|
|
213
|
+
|
|
214
|
+
**SettingsScreen.tsx** (src/screens/)
|
|
215
|
+
- Demonstrates: optIn/OutTracking(), reset(), flush(), hasOptedOutTracking()
|
|
216
|
+
- GDPR compliance controls
|
|
217
|
+
- Data management (reset all data)
|
|
218
|
+
- Manual flush for testing
|
|
219
|
+
- SDK information display
|
|
220
|
+
|
|
221
|
+
**tracking.ts** (src/constants/)
|
|
222
|
+
- Centralized event names (Events object)
|
|
223
|
+
- Property names (Properties object)
|
|
224
|
+
- Super property keys (SuperProperties object)
|
|
225
|
+
- All constants are `as const` for type safety
|
|
226
|
+
|
|
227
|
+
## Key Concepts Demonstrated
|
|
228
|
+
|
|
229
|
+
### 1. Initialization Lifecycle
|
|
230
|
+
```typescript
|
|
231
|
+
// Context handles initialization automatically
|
|
232
|
+
useEffect(() => {
|
|
233
|
+
const initMixpanel = async () => {
|
|
234
|
+
const instance = new Mixpanel(token, trackAutomaticEvents, useNative);
|
|
235
|
+
await instance.init();
|
|
236
|
+
instance.registerSuperProperties({...});
|
|
237
|
+
setMixpanel(instance);
|
|
238
|
+
setIsInitialized(true);
|
|
239
|
+
};
|
|
240
|
+
initMixpanel();
|
|
241
|
+
}, [token]);
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### 2. Loading State Management
|
|
245
|
+
```typescript
|
|
246
|
+
// Components can check initialization state
|
|
247
|
+
const { isInitialized, isLoading, error } = useMixpanel();
|
|
248
|
+
|
|
249
|
+
// Disable buttons until ready
|
|
250
|
+
<ActionButton
|
|
251
|
+
disabled={!isInitialized}
|
|
252
|
+
onPress={handleAction}
|
|
253
|
+
/>
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### 3. Error Handling
|
|
257
|
+
```typescript
|
|
258
|
+
// Context catches initialization errors
|
|
259
|
+
try {
|
|
260
|
+
await instance.init();
|
|
261
|
+
} catch (err) {
|
|
262
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
263
|
+
console.error('Failed to initialize Mixpanel:', error);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// ErrorBoundary catches React errors
|
|
267
|
+
<ErrorBoundary>
|
|
268
|
+
<MixpanelProvider>
|
|
269
|
+
{/* app */}
|
|
270
|
+
</MixpanelProvider>
|
|
271
|
+
</ErrorBoundary>
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### 4. TypeScript Strict Mode
|
|
275
|
+
- All files compile without errors
|
|
276
|
+
- Proper typing for all props and state
|
|
277
|
+
- Event/property names are type-safe constants
|
|
278
|
+
- No `any` types except in Record<string, any> for event properties
|
|
279
|
+
|
|
280
|
+
### 5. Educational Components
|
|
281
|
+
Every screen includes an InfoCard titled "What's Happening?" that explains:
|
|
282
|
+
- Which SDK methods are being used
|
|
283
|
+
- Why you'd use this pattern
|
|
284
|
+
- What data is being sent
|
|
285
|
+
|
|
286
|
+
## Common Modifications
|
|
287
|
+
|
|
288
|
+
### Adding a New Event
|
|
289
|
+
|
|
290
|
+
1. **Define constant** (src/constants/tracking.ts):
|
|
291
|
+
```typescript
|
|
292
|
+
export const Events = {
|
|
293
|
+
// ... existing events
|
|
294
|
+
FEATURE_USED: 'Feature Used',
|
|
295
|
+
};
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
2. **Track in component**:
|
|
299
|
+
```typescript
|
|
300
|
+
const handleFeatureUse = () => {
|
|
301
|
+
track(Events.FEATURE_USED, {
|
|
302
|
+
feature_name: 'search',
|
|
303
|
+
timestamp: new Date().toISOString(),
|
|
304
|
+
});
|
|
305
|
+
};
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### Adding a New Screen
|
|
309
|
+
|
|
310
|
+
1. **Create screen file** (src/screens/NewScreen.tsx):
|
|
311
|
+
```typescript
|
|
312
|
+
import {useMixpanel} from '../contexts/MixpanelContext';
|
|
313
|
+
import {Events, Properties} from '../constants/tracking';
|
|
314
|
+
|
|
315
|
+
export const NewScreen = () => {
|
|
316
|
+
const {track, isInitialized} = useMixpanel();
|
|
317
|
+
|
|
318
|
+
useEffect(() => {
|
|
319
|
+
if (isInitialized) {
|
|
320
|
+
track(Events.SCREEN_VIEWED, {
|
|
321
|
+
[Properties.SCREEN_NAME]: 'NewScreen',
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
}, [isInitialized, track]);
|
|
325
|
+
|
|
326
|
+
// ... component logic
|
|
327
|
+
};
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
2. **Add to navigation** (src/App.tsx):
|
|
331
|
+
```typescript
|
|
332
|
+
<Tab.Screen
|
|
333
|
+
name="New"
|
|
334
|
+
component={NewScreen}
|
|
335
|
+
options={{
|
|
336
|
+
tabBarLabel: 'New',
|
|
337
|
+
tabBarIcon: ({color}) => <Text style={{fontSize: 20, color}}>🎯</Text>,
|
|
338
|
+
}}
|
|
339
|
+
/>
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Changing Mixpanel Configuration
|
|
343
|
+
|
|
344
|
+
**In MixpanelProvider** (src/contexts/MixpanelContext.tsx):
|
|
345
|
+
```typescript
|
|
346
|
+
// Change automatic event tracking
|
|
347
|
+
trackAutomaticEvents={false}
|
|
348
|
+
|
|
349
|
+
// Change native/JS mode
|
|
350
|
+
useNative={false} // Forces JavaScript implementation
|
|
351
|
+
|
|
352
|
+
// Modify default super properties
|
|
353
|
+
instance.registerSuperProperties({
|
|
354
|
+
[SuperProperties.APP_VERSION]: '2.0.0', // Update version
|
|
355
|
+
'Custom Property': 'value', // Add custom property
|
|
356
|
+
});
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
## Testing Guidelines
|
|
360
|
+
|
|
361
|
+
### Running Tests
|
|
362
|
+
```bash
|
|
363
|
+
npm test # Run all tests
|
|
364
|
+
npm test -- --coverage # With coverage report
|
|
365
|
+
npm test -- --watch # Watch mode
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### Test Structure
|
|
369
|
+
- **Unit tests**: Components and contexts in isolation
|
|
370
|
+
- **Mock Mixpanel SDK**: Already configured in MixpanelContext.test.tsx
|
|
371
|
+
- **Test initialization**: Verify loading → initialized state transition
|
|
372
|
+
- **Test error handling**: Provider catches and exposes errors
|
|
373
|
+
|
|
374
|
+
### Writing New Tests
|
|
375
|
+
```typescript
|
|
376
|
+
// Mock Mixpanel SDK
|
|
377
|
+
jest.mock('mixpanel-react-native', () => ({
|
|
378
|
+
Mixpanel: jest.fn().mockImplementation(() => ({
|
|
379
|
+
init: jest.fn().mockResolvedValue(undefined),
|
|
380
|
+
track: jest.fn(),
|
|
381
|
+
// ... other methods
|
|
382
|
+
})),
|
|
383
|
+
}));
|
|
384
|
+
|
|
385
|
+
// Test component with context
|
|
386
|
+
render(
|
|
387
|
+
<MixpanelProvider token="test-token">
|
|
388
|
+
<YourComponent />
|
|
389
|
+
</MixpanelProvider>
|
|
390
|
+
);
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
## TypeScript Configuration
|
|
394
|
+
|
|
395
|
+
### Strict Mode Enabled
|
|
396
|
+
```json
|
|
397
|
+
{
|
|
398
|
+
"compilerOptions": {
|
|
399
|
+
"strict": true, // All strict checks enabled
|
|
400
|
+
"typeRoots": ["./node_modules/@types", "./src/@types"]
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
### Type Checking
|
|
406
|
+
```bash
|
|
407
|
+
npx tsc --noEmit # Check types without emitting files
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### Common Type Issues
|
|
411
|
+
- **Environment variables**: Defined in src/@types/env.d.ts
|
|
412
|
+
- **Mixpanel instance**: Can be null before initialization (check isInitialized)
|
|
413
|
+
- **Async methods**: alias() and flush() return Promise<void>
|
|
414
|
+
|
|
415
|
+
## Debugging
|
|
416
|
+
|
|
417
|
+
### Enable Logging
|
|
418
|
+
Logging is automatically enabled in development (`__DEV__`):
|
|
419
|
+
```typescript
|
|
420
|
+
if (__DEV__) {
|
|
421
|
+
instance.setLoggingEnabled(true);
|
|
422
|
+
}
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
### Console Output
|
|
426
|
+
Look for `[Mixpanel]` prefixed logs:
|
|
427
|
+
- Event tracking confirmations
|
|
428
|
+
- Network requests
|
|
429
|
+
- Error messages
|
|
430
|
+
- Queue status
|
|
431
|
+
|
|
432
|
+
### Verify Events
|
|
433
|
+
1. **Console**: Check for `[Mixpanel]` logs
|
|
434
|
+
2. **Network**: Use React Native Debugger to see network requests
|
|
435
|
+
3. **Dashboard**: Events appear in Mixpanel Live View (may take 1-2 minutes)
|
|
436
|
+
4. **Distinct ID**: Call `await mixpanel.getDistinctId()` to verify initialization
|
|
437
|
+
|
|
438
|
+
### Common Issues
|
|
439
|
+
|
|
440
|
+
**Events not tracked?**
|
|
441
|
+
- Check `isInitialized` is true
|
|
442
|
+
- Verify token is set correctly
|
|
443
|
+
- Check opt-out status: `await hasOptedOutTracking()`
|
|
444
|
+
- Manually flush: `await flush()`
|
|
445
|
+
|
|
446
|
+
**TypeScript errors?**
|
|
447
|
+
- Clear Metro cache: `npm start -- --reset-cache`
|
|
448
|
+
- Verify all dependencies installed: `npm install`
|
|
449
|
+
- Check tsconfig.json is correct
|
|
450
|
+
|
|
451
|
+
**Build errors?**
|
|
452
|
+
- iOS: `cd ios && pod install && cd ..`
|
|
453
|
+
- Android: `cd android && ./gradlew clean && cd ..`
|
|
454
|
+
- Clear node_modules: `rm -rf node_modules && npm install`
|
|
455
|
+
|
|
456
|
+
## Best Practices for Modifications
|
|
457
|
+
|
|
458
|
+
### DO:
|
|
459
|
+
✅ Use constants for event/property names
|
|
460
|
+
✅ Check `isInitialized` before tracking
|
|
461
|
+
✅ Include timestamps in event properties
|
|
462
|
+
✅ Add "What's Happening?" explanations for new features
|
|
463
|
+
✅ Follow existing file structure and naming conventions
|
|
464
|
+
✅ Update TypeScript types when adding new interfaces
|
|
465
|
+
✅ Test on both iOS and Android
|
|
466
|
+
✅ Keep Context API pattern for Mixpanel access
|
|
467
|
+
|
|
468
|
+
### DON'T:
|
|
469
|
+
❌ Hardcode event names (use constants)
|
|
470
|
+
❌ Track before initialization
|
|
471
|
+
❌ Use `any` type (use strict TypeScript)
|
|
472
|
+
❌ Skip error handling
|
|
473
|
+
❌ Track PII without user consent
|
|
474
|
+
❌ Over-track (every render/state change)
|
|
475
|
+
❌ Mix navigation patterns (stick to bottom tabs)
|
|
476
|
+
|
|
477
|
+
## Educational Purpose
|
|
478
|
+
|
|
479
|
+
This sample app is designed to teach, not just demonstrate. When making changes:
|
|
480
|
+
|
|
481
|
+
1. **Preserve educational value**: Keep "What's Happening?" cards updated
|
|
482
|
+
2. **Maintain simplicity**: This bridges simple→complex, don't overcomplicate
|
|
483
|
+
3. **Document patterns**: Add comments explaining WHY, not just WHAT
|
|
484
|
+
4. **Keep it copy-pasteable**: Developers should be able to copy patterns directly
|
|
485
|
+
|
|
486
|
+
## Integration with Parent SDK
|
|
487
|
+
|
|
488
|
+
This sample lives at: `Samples/MixpanelStarter/`
|
|
489
|
+
|
|
490
|
+
**SDK dependency**: Uses `file:../..` to reference parent mixpanel-react-native package
|
|
491
|
+
|
|
492
|
+
**When SDK changes**:
|
|
493
|
+
```bash
|
|
494
|
+
cd Samples/MixpanelStarter
|
|
495
|
+
rm -rf node_modules
|
|
496
|
+
npm install # Re-links to parent SDK
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
## Documentation Maintenance
|
|
500
|
+
|
|
501
|
+
### When to Update Docs
|
|
502
|
+
|
|
503
|
+
**README.md**: User-facing changes (new features, setup steps, troubleshooting)
|
|
504
|
+
**INTEGRATION_GUIDE.md**: Integration patterns, API changes, best practices
|
|
505
|
+
**CLAUDE.md**: Architecture changes, new patterns, file structure updates
|
|
506
|
+
|
|
507
|
+
### Documentation Standards
|
|
508
|
+
- Keep examples up-to-date with actual code
|
|
509
|
+
- Include both "why" and "how" explanations
|
|
510
|
+
- Use code snippets from real files (with file paths)
|
|
511
|
+
- Maintain consistent formatting and style
|
|
512
|
+
|
|
513
|
+
## Version Information
|
|
514
|
+
|
|
515
|
+
**Created**: 2025
|
|
516
|
+
**React Native Version**: 0.82.1
|
|
517
|
+
**Mixpanel SDK**: 3.1.2
|
|
518
|
+
**Target RN Version**: 0.70+
|
|
519
|
+
|
|
520
|
+
## AI Assistant Notes
|
|
521
|
+
|
|
522
|
+
When working with this codebase:
|
|
523
|
+
|
|
524
|
+
1. **Preserve the educational mission**: This is a learning tool, not just a demo
|
|
525
|
+
2. **Maintain Context API pattern**: Don't switch to Redux/MobX/etc
|
|
526
|
+
3. **Keep TypeScript strict**: No `any` types, proper inference
|
|
527
|
+
4. **Follow existing patterns**: File naming, import order, component structure
|
|
528
|
+
5. **Test changes**: Run `npm test` and `npx tsc --noEmit` before completing
|
|
529
|
+
6. **Update documentation**: README, INTEGRATION_GUIDE, and CLAUDE.md as needed
|
|
530
|
+
|
|
531
|
+
## Resources
|
|
532
|
+
|
|
533
|
+
- **Parent SDK**: `../../` (mixpanel-react-native)
|
|
534
|
+
- **Parent CLAUDE.md**: `../../CLAUDE.md`
|
|
535
|
+
- **Mixpanel Docs**: https://docs.mixpanel.com/docs/tracking/advanced/react-native
|
|
536
|
+
- **React Navigation**: https://reactnavigation.org/
|
|
537
|
+
|
|
538
|
+
Last updated: 2025-05-11
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
source 'https://rubygems.org'
|
|
2
|
+
|
|
3
|
+
# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
|
|
4
|
+
ruby ">= 2.6.10"
|
|
5
|
+
|
|
6
|
+
# Exclude problematic versions of cocoapods and activesupport that causes build failures.
|
|
7
|
+
gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1'
|
|
8
|
+
gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0'
|
|
9
|
+
gem 'xcodeproj', '< 1.26.0'
|
|
10
|
+
gem 'concurrent-ruby', '< 1.3.4'
|
|
11
|
+
|
|
12
|
+
# Ruby 3.4.0 has removed some libraries from the standard library.
|
|
13
|
+
gem 'bigdecimal'
|
|
14
|
+
gem 'logger'
|
|
15
|
+
gem 'benchmark'
|
|
16
|
+
gem 'mutex_m'
|