@influto/react-native-sdk 1.1.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/README.md +50 -2
- package/lib/InfluTo.d.ts +82 -1
- package/lib/InfluTo.js +179 -0
- package/lib/components/ReferralCodeInput.d.ts +125 -0
- package/lib/components/ReferralCodeInput.js +397 -0
- package/lib/components/index.d.ts +7 -0
- package/lib/components/index.js +10 -0
- package/lib/index.js +2 -0
- package/lib/types.d.ts +65 -0
- package/lib/ui.d.ts +11 -0
- package/lib/ui.js +27 -0
- package/package.json +13 -1
- package/src/InfluTo.ts +199 -1
- package/src/components/ReferralCodeInput.tsx +596 -0
- package/src/components/index.ts +8 -0
- package/src/index.ts +3 -0
- package/src/types.ts +77 -0
- package/src/ui.ts +12 -0
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/';
|
|
@@ -256,6 +258,202 @@ class InfluToSDK {
|
|
|
256
258
|
return await AsyncStorage.getItem(STORAGE_KEYS.REFERRAL_CODE);
|
|
257
259
|
}
|
|
258
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
|
+
|
|
259
457
|
/**
|
|
260
458
|
* Clear stored attribution data
|
|
261
459
|
*
|