@influto/react-native-sdk 1.0.0 → 1.2.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/src/InfluTo.ts CHANGED
@@ -28,7 +28,9 @@ import type {
28
28
  AttributionResult,
29
29
  Campaign,
30
30
  TrackEventOptions,
31
- DeviceInfo
31
+ DeviceInfo,
32
+ CodeValidationResult,
33
+ SetCodeResult
32
34
  } from './types';
33
35
 
34
36
  const STORAGE_PREFIX = '@influto/';
@@ -41,7 +43,7 @@ const STORAGE_KEYS = {
41
43
 
42
44
  class InfluToSDK {
43
45
  private config: InfluToConfig | null = null;
44
- private apiUrl: string = 'https://api.influ.to/api';
46
+ private apiUrl: string = 'https://influ.to/api';
45
47
  private isInitialized: boolean = false;
46
48
 
47
49
  /**
@@ -132,6 +134,25 @@ class InfluToSDK {
132
134
  await AsyncStorage.setItem(STORAGE_KEYS.ATTRIBUTION, JSON.stringify(attribution));
133
135
  await AsyncStorage.setItem(STORAGE_KEYS.REFERRAL_CODE, response.referral_code);
134
136
 
137
+ // 🎯 AUTO-INTEGRATION: Set RevenueCat attribute if available
138
+ try {
139
+ // @ts-ignore - RevenueCat might not be installed
140
+ const Purchases = require('react-native-purchases').default;
141
+ if (Purchases && Purchases.setAttributes) {
142
+ await Purchases.setAttributes({
143
+ referral_code: response.referral_code
144
+ });
145
+ if (this.config?.debug) {
146
+ console.log('[InfluTo] ✅ Referral code set in RevenueCat automatically');
147
+ }
148
+ }
149
+ } catch (e) {
150
+ // RevenueCat not installed - that's okay, developer can set manually
151
+ if (this.config?.debug) {
152
+ console.log('[InfluTo] RevenueCat not found - set referral_code manually');
153
+ }
154
+ }
155
+
135
156
  if (this.config?.debug) {
136
157
  console.log('[InfluTo] ✅ Attribution found:', response.referral_code);
137
158
  }
@@ -237,6 +258,202 @@ class InfluToSDK {
237
258
  return await AsyncStorage.getItem(STORAGE_KEYS.REFERRAL_CODE);
238
259
  }
239
260
 
261
+ /**
262
+ * Get prefilled referral code (if user came via attribution link)
263
+ *
264
+ * Use this to pre-fill a promo code input field
265
+ *
266
+ * @returns Referral code if attribution exists, null otherwise
267
+ */
268
+ async getPrefilledCode(): Promise<string | null> {
269
+ const attribution = await AsyncStorage.getItem(STORAGE_KEYS.ATTRIBUTION);
270
+
271
+ if (attribution) {
272
+ const parsed = JSON.parse(attribution);
273
+ return parsed.attributed ? parsed.referralCode : null;
274
+ }
275
+
276
+ return null;
277
+ }
278
+
279
+ /**
280
+ * Validate a referral/promo code
281
+ *
282
+ * Check if a code is valid without applying it.
283
+ * Use this when user manually enters a code in your app.
284
+ *
285
+ * @param code - The referral code to validate
286
+ * @returns Validation result with campaign info if valid
287
+ *
288
+ * @example
289
+ * ```typescript
290
+ * const result = await InfluTo.validateCode('FITGURU30');
291
+ *
292
+ * if (result.valid) {
293
+ * console.log('Campaign:', result.campaign.name);
294
+ * console.log('Commission:', result.campaign.commission_percentage + '%');
295
+ * // Show custom offer based on campaign
296
+ * } else {
297
+ * console.log('Invalid code:', result.error);
298
+ * }
299
+ * ```
300
+ */
301
+ async validateCode(code: string): Promise<CodeValidationResult> {
302
+ if (!this.isInitialized) {
303
+ return {
304
+ valid: false,
305
+ error: 'SDK not initialized',
306
+ error_code: 'NETWORK_ERROR'
307
+ };
308
+ }
309
+
310
+ try {
311
+ const response = await this.apiRequest('/sdk/validate-code', {
312
+ method: 'POST',
313
+ body: JSON.stringify({ code: code.trim().toUpperCase() })
314
+ });
315
+
316
+ return response as CodeValidationResult;
317
+ } catch (error) {
318
+ if (this.config?.debug) {
319
+ console.error('[InfluTo] Code validation failed:', error);
320
+ }
321
+
322
+ return {
323
+ valid: false,
324
+ error: 'Network error or invalid response',
325
+ error_code: 'NETWORK_ERROR'
326
+ };
327
+ }
328
+ }
329
+
330
+ /**
331
+ * Manually set a referral code
332
+ *
333
+ * Use this when user enters a promo code manually (not from link click).
334
+ * This will:
335
+ * 1. Store the code locally
336
+ * 2. Set it in RevenueCat attributes automatically
337
+ * 3. Record the attribution with backend
338
+ *
339
+ * @param code - The referral code to set
340
+ * @param appUserId - Optional user ID (if available)
341
+ * @returns Result with success status
342
+ *
343
+ * @example
344
+ * ```typescript
345
+ * // User enters code manually
346
+ * const result = await InfluTo.setReferralCode('FITGURU30');
347
+ *
348
+ * if (result.success) {
349
+ * console.log('Code applied successfully');
350
+ * // Show appropriate paywall/offer
351
+ * }
352
+ * ```
353
+ */
354
+ async setReferralCode(code: string, appUserId?: string): Promise<SetCodeResult> {
355
+ if (!this.isInitialized) {
356
+ return {
357
+ success: false,
358
+ message: 'SDK not initialized'
359
+ };
360
+ }
361
+
362
+ const normalizedCode = code.trim().toUpperCase();
363
+
364
+ try {
365
+ // Store locally
366
+ await AsyncStorage.setItem(STORAGE_KEYS.REFERRAL_CODE, normalizedCode);
367
+
368
+ // Store attribution record
369
+ const attribution: AttributionResult = {
370
+ attributed: true,
371
+ referralCode: normalizedCode,
372
+ attributionMethod: 'manual_entry',
373
+ clickedAt: new Date().toISOString(),
374
+ message: 'Manually entered code'
375
+ };
376
+ await AsyncStorage.setItem(STORAGE_KEYS.ATTRIBUTION, JSON.stringify(attribution));
377
+
378
+ // Set in RevenueCat automatically
379
+ try {
380
+ const Purchases = require('react-native-purchases').default;
381
+ if (Purchases && Purchases.setAttributes) {
382
+ await Purchases.setAttributes({
383
+ referral_code: normalizedCode
384
+ });
385
+
386
+ if (this.config?.debug) {
387
+ console.log('[InfluTo] ✅ Referral code set in RevenueCat');
388
+ }
389
+ }
390
+ } catch (e) {
391
+ if (this.config?.debug) {
392
+ console.warn('[InfluTo] RevenueCat not available - set manually');
393
+ }
394
+ }
395
+
396
+ // Record with backend
397
+ const response = await this.apiRequest('/sdk/set-referral-code', {
398
+ method: 'POST',
399
+ body: JSON.stringify({
400
+ code: normalizedCode,
401
+ app_user_id: appUserId
402
+ })
403
+ });
404
+
405
+ return response as SetCodeResult;
406
+ } catch (error) {
407
+ if (this.config?.debug) {
408
+ console.error('[InfluTo] Failed to set referral code:', error);
409
+ }
410
+
411
+ return {
412
+ success: false,
413
+ message: 'Failed to set code: ' + (error as Error).message
414
+ };
415
+ }
416
+ }
417
+
418
+ /**
419
+ * Validate and apply a referral code (combined operation)
420
+ *
421
+ * This is a convenience method that validates a code and applies it if valid.
422
+ * Use this for one-step validation + application.
423
+ *
424
+ * @param code - The referral code to validate and apply
425
+ * @param appUserId - Optional user ID
426
+ * @returns Validation result. If valid, code is automatically applied.
427
+ *
428
+ * @example
429
+ * ```typescript
430
+ * const result = await InfluTo.applyCode('FITGURU30', userId);
431
+ *
432
+ * if (result.valid) {
433
+ * // Code validated AND applied automatically
434
+ * showCustomOffer(result.campaign);
435
+ * } else {
436
+ * Alert.alert('Invalid Code', result.error);
437
+ * }
438
+ * ```
439
+ */
440
+ async applyCode(code: string, appUserId?: string): Promise<CodeValidationResult & { applied?: boolean }> {
441
+ // First validate
442
+ const validation = await this.validateCode(code);
443
+
444
+ if (!validation.valid) {
445
+ return { ...validation, applied: false };
446
+ }
447
+
448
+ // If valid, apply it
449
+ const setResult = await this.setReferralCode(code, appUserId);
450
+
451
+ return {
452
+ ...validation,
453
+ applied: setResult.success
454
+ };
455
+ }
456
+
240
457
  /**
241
458
  * Clear stored attribution data
242
459
  *