react-native-insider 7.0.5 → 7.0.6

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.
Files changed (30) hide show
  1. package/.claude/commands/pr-description.md +40 -0
  2. package/.claude/settings.json +34 -0
  3. package/RNInsider.podspec +2 -2
  4. package/android/.gradle/8.10/checksums/checksums.lock +0 -0
  5. package/android/.gradle/8.10/dependencies-accessors/gc.properties +0 -0
  6. package/android/.gradle/8.10/fileChanges/last-build.bin +0 -0
  7. package/android/.gradle/8.10/fileHashes/fileHashes.lock +0 -0
  8. package/android/.gradle/8.10/gc.properties +0 -0
  9. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  10. package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
  11. package/android/.gradle/config.properties +2 -0
  12. package/android/.gradle/vcs-1/gc.properties +0 -0
  13. package/android/local.properties +8 -0
  14. package/android/src/main/java/com/useinsider/react/RNInsiderModule.java +34 -33
  15. package/android/src/main/java/com/useinsider/react/RNUtils.java +197 -8
  16. package/index.d.ts +14 -0
  17. package/index.js +41 -29
  18. package/ios/RNInsider/RNInsider.m +56 -19
  19. package/ios/RNInsider/RNUtils.h +26 -0
  20. package/ios/RNInsider/RNUtils.m +250 -0
  21. package/ios/RNInsider.xcodeproj/project.pbxproj +6 -0
  22. package/ios/RNInsider.xcodeproj/project.xcworkspace/xcuserdata/heysem.katibi.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  23. package/ios/RNInsider.xcodeproj/project.xcworkspace/xcuserdata/heysem.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  24. package/ios/RNInsider.xcodeproj/xcuserdata/heysem.katibi.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  25. package/ios/RNInsider.xcodeproj/xcuserdata/heysem.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +6 -0
  26. package/ios/RNInsider.xcodeproj/xcuserdata/heysem.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  27. package/package.json +1 -1
  28. package/src/InsiderEvent.js +10 -10
  29. package/src/InsiderProduct.js +35 -66
  30. package/src/InsiderUser.js +2 -2
package/index.js CHANGED
@@ -184,7 +184,7 @@ export default class RNInsider {
184
184
  return;
185
185
  }
186
186
  try {
187
- Insider.itemPurchased(uniqueSaleID, product.productMustMap, product.productOptMap);
187
+ Insider.itemPurchased(uniqueSaleID, product.requiredFields, product.optionalFields, product.customParameters);
188
188
  } catch (error) {
189
189
  Insider.putErrorLog(generateJSONErrorString(error));
190
190
  }
@@ -197,7 +197,7 @@ export default class RNInsider {
197
197
  return;
198
198
  }
199
199
  try {
200
- Insider.itemAddedToCart(product.productMustMap, product.productOptMap);
200
+ Insider.itemAddedToCart(product.requiredFields, product.optionalFields, product.customParameters);
201
201
  } catch (error) {
202
202
  Insider.putErrorLog(generateJSONErrorString(error));
203
203
  }
@@ -225,16 +225,16 @@ export default class RNInsider {
225
225
  }
226
226
  }
227
227
 
228
- static itemAddedToWishlist(product: RNInsiderProduct) {
228
+ static itemAddedToWishlist(product) {
229
229
  if (shouldNotProceed() || product == null) return;
230
230
  try {
231
- Insider.itemAddedToWishlist(product.productMustMap, product.productOptMap);
231
+ Insider.itemAddedToWishlist(product.requiredFields, product.optionalFields, product.customParameters);
232
232
  } catch (error) {
233
233
  Insider.putErrorLog(generateJSONErrorString(error));
234
234
  }
235
235
  }
236
236
 
237
- static itemRemovedFromWishlist(productID: string) {
237
+ static itemRemovedFromWishlist(productID) {
238
238
  if (shouldNotProceed() || productID == null) return;
239
239
  try {
240
240
  Insider.itemRemovedFromWishlist(productID);
@@ -329,7 +329,7 @@ export default class RNInsider {
329
329
  return;
330
330
  }
331
331
  try {
332
- Insider.getSmartRecommendationWithProduct(product.productMustMap, product.productOptMap, recommendationID, locale, (recommendation) => {
332
+ Insider.getSmartRecommendationWithProduct(product.requiredFields, product.optionalFields, product.customParameters, recommendationID, locale, (recommendation) => {
333
333
  callback(recommendation);
334
334
  });
335
335
  } catch (error) {
@@ -379,7 +379,7 @@ export default class RNInsider {
379
379
  return;
380
380
  }
381
381
  try {
382
- Insider.clickSmartRecommendationProduct(recommendationID, product.productMustMap, product.productOptMap);
382
+ Insider.clickSmartRecommendationProduct(recommendationID, product.requiredFields, product.optionalFields, product.customParameters);
383
383
  } catch (error) {
384
384
  Insider.putErrorLog(generateJSONErrorString(error));
385
385
  }
@@ -555,7 +555,7 @@ export default class RNInsider {
555
555
  return;
556
556
  }
557
557
  try {
558
- Insider.visitProductDetailPage(product.productMustMap, product.productOptMap);
558
+ Insider.visitProductDetailPage(product.requiredFields, product.optionalFields, product.customParameters);
559
559
  } catch (error) {
560
560
  Insider.putErrorLog(generateJSONErrorString(error));
561
561
  }
@@ -567,35 +567,35 @@ export default class RNInsider {
567
567
  showParameterWarningLog("visitCartPage", [{ type: 'object', value: products }]);
568
568
  return;
569
569
  }
570
- let mappedProducts = new Array(products.length);
571
570
  try {
572
- products.forEach((product, i) => {
573
- let productMap = {};
574
- productMap['productMustMap'] = product.productMustMap;
575
- productMap['productOptMap'] = product.productOptMap;
576
- mappedProducts[i] = productMap;
577
- });
571
+ const mappedProducts = products.map(product => ({
572
+ requiredFields: product.requiredFields,
573
+ optionalFields: product.optionalFields,
574
+ customParameters: product.customParameters
575
+ }));
578
576
  Insider.visitCartPage(mappedProducts);
579
577
  } catch (error) {
580
578
  Insider.putErrorLog(generateJSONErrorString(error));
581
579
  }
582
580
  }
583
581
 
584
- static visitWishlistPage(products: Array<RNInsiderProduct>) {
585
- if (shouldNotProceed() || products == null) return;
586
- let mappedProducts = new Array(products.length);
587
- try {
588
- products.forEach((product, i) => {
589
- let productMap = {};
590
- productMap['productMustMap'] = product.productMustMap;
591
- productMap['productOptMap'] = product.productOptMap;
592
- mappedProducts[i] = productMap;
593
- });
594
- Insider.visitWishlistPage(mappedProducts);
595
- } catch (error) {
596
- Insider.putErrorLog(generateJSONErrorString(error));
597
- }
582
+ static visitWishlistPage(products) {
583
+ if (shouldNotProceed() || products == null) return;
584
+ if (checkParameters([{ type: 'object', value: products }])) {
585
+ showParameterWarningLog("visitWishlistPage", [{ type: 'object', value: products }]);
586
+ return;
598
587
  }
588
+ try {
589
+ const mappedProducts = products.map(product => ({
590
+ requiredFields: product.requiredFields,
591
+ optionalFields: product.optionalFields,
592
+ customParameters: product.customParameters
593
+ }));
594
+ Insider.visitWishlistPage(mappedProducts);
595
+ } catch (error) {
596
+ Insider.putErrorLog(generateJSONErrorString(error));
597
+ }
598
+ }
599
599
 
600
600
  static startTrackingGeofence() {
601
601
  if (shouldNotProceed()) return;
@@ -848,4 +848,16 @@ export default class RNInsider {
848
848
  Insider.putErrorLog(generateJSONErrorString(error));
849
849
  }
850
850
  }
851
+
852
+ static handleURL(url) {
853
+ if (shouldNotProceed()) return;
854
+
855
+ try {
856
+ if (Platform.OS === 'android') return;
857
+
858
+ Insider.handleURL(url);
859
+ } catch (error) {
860
+ Insider.putErrorLog(generateJSONErrorString(error));
861
+ }
862
+ }
851
863
  }
@@ -1,5 +1,6 @@
1
1
  #import "RNInsider.h"
2
2
  #import "RNNotificationHandler.h"
3
+ #import "RNUtils.h"
3
4
 
4
5
  #if __has_include(<InsiderMobile/Insider.h>)
5
6
  #import <InsiderMobile/Insider.h>
@@ -53,9 +54,9 @@ RCT_EXPORT_METHOD(reinitWithPartnerName:(NSString *)partnerName) {
53
54
  }
54
55
  }
55
56
 
56
- RCT_EXPORT_METHOD(tagEvent:(NSString *)eventName withParameters:(NSDictionary *)parameters) {
57
+ RCT_EXPORT_METHOD(tagEvent:(NSString *)eventName withParameters:(NSArray *)parameters) {
57
58
  @try {
58
- [[Insider tagEvent:eventName].addParameters(parameters) build];
59
+ [[RNUtils parseEventFromEventName:eventName andParameters:parameters] build];
59
60
  } @catch (NSException *e){
60
61
  [Insider sendError:e desc:[NSString stringWithFormat:@"%s:%d", __func__, __LINE__]];
61
62
  }
@@ -70,9 +71,12 @@ RCT_EXPORT_METHOD(setGender:(int)gender) {
70
71
  }
71
72
  }
72
73
 
73
- RCT_EXPORT_METHOD(setBirthday:(NSString *)value) {
74
+ RCT_EXPORT_METHOD(setBirthday:(NSString *)birthday) {
74
75
  @try {
75
- [InsiderHybrid setBirthday:value];
76
+ long long epochMillis = birthday.longLongValue;
77
+ NSTimeInterval epochSeconds = ((NSTimeInterval)epochMillis) / 1000.0;
78
+ NSDate *dateValue = [NSDate dateWithTimeIntervalSince1970:epochSeconds];
79
+ [Insider getCurrentUser].setBirthday(dateValue);
76
80
  } @catch (NSException *e) {
77
81
  [Insider sendError:e desc:[NSString stringWithFormat:@"%s:%d", __func__, __LINE__]];
78
82
  }
@@ -166,6 +170,20 @@ RCT_EXPORT_METHOD(setPhoneNumber:(NSString *)value) {
166
170
  }
167
171
  }
168
172
 
173
+ RCT_EXPORT_METHOD(handleURL:(NSString *)value) {
174
+ @try {
175
+ NSURL *url = [NSURL URLWithString:value];
176
+
177
+ if (url == nil) {
178
+ return;
179
+ }
180
+
181
+ [Insider handleUrl:url];
182
+ } @catch (NSException *e) {
183
+ [Insider sendError:e desc:[NSString stringWithFormat:@"%s:%d", __func__, __LINE__]];
184
+ }
185
+ }
186
+
169
187
  RCT_EXPORT_METHOD(setPushOptin:(BOOL)value) {
170
188
  @try {
171
189
  [Insider getCurrentUser].setPushOptin(value);
@@ -317,7 +335,10 @@ RCT_EXPORT_METHOD(setCustomAttributeWithBoolean:(NSString *)key value:(BOOL)valu
317
335
 
318
336
  RCT_EXPORT_METHOD(setCustomAttributeWithDate:(NSString *)key value:(NSString *)value) {
319
337
  @try {
320
- [InsiderHybrid setCustomAttributeWithDate:key value:value];
338
+ long long epochMillis = value.longLongValue;
339
+ NSTimeInterval epochSeconds = ((NSTimeInterval)epochMillis) / 1000.0;
340
+ NSDate *dateValue = [NSDate dateWithTimeIntervalSince1970:epochSeconds];
341
+ [Insider getCurrentUser].setCustomAttributeWithDate(key, dateValue);
321
342
  } @catch (NSException *e) {
322
343
  [Insider sendError:e desc:[NSString stringWithFormat:@"%s:%d", __func__, __LINE__]];
323
344
  }
@@ -364,18 +385,18 @@ RCT_EXPORT_METHOD(signUpConfirmation) {
364
385
  }
365
386
 
366
387
  // Insider Product
367
- RCT_EXPORT_METHOD(itemPurchased:(NSString *)saleID productMustMap:(NSDictionary *)productMustMap productOptMap:(NSDictionary *)productOptMap) {
388
+ RCT_EXPORT_METHOD(itemPurchased:(NSString *)saleID requiredFields:(NSDictionary *)requiredFields optionalFields:(NSDictionary *)optionalFields customParameters:(NSArray *)customParameters) {
368
389
  @try {
369
- InsiderProduct *product = [InsiderHybrid createProduct:productMustMap productOptMap:productOptMap];
390
+ InsiderProduct *product = [RNUtils parseProductFromRequiredFields:requiredFields andOptionalFields:optionalFields andCustomParameters:customParameters];
370
391
  [Insider itemPurchasedWithSaleID:saleID product:product];
371
392
  } @catch (NSException *e){
372
393
  [Insider sendError:e desc:[NSString stringWithFormat:@"%s:%d", __func__, __LINE__]];
373
394
  }
374
395
  }
375
396
 
376
- RCT_EXPORT_METHOD(itemAddedToCart:(NSDictionary *)productMustMap productOptMap:(NSDictionary *)productOptMap) {
397
+ RCT_EXPORT_METHOD(itemAddedToCart:(NSDictionary *)requiredFields optionalFields:(NSDictionary *)optionalFields customParameters:(NSArray *)customParameters) {
377
398
  @try {
378
- InsiderProduct *product = [InsiderHybrid createProduct:productMustMap productOptMap:productOptMap];
399
+ InsiderProduct *product = [RNUtils parseProductFromRequiredFields:requiredFields andOptionalFields:optionalFields andCustomParameters:customParameters];
379
400
  [Insider itemAddedToCartWithProduct:product];
380
401
  } @catch (NSException *e){
381
402
  [Insider sendError:e desc:[NSString stringWithFormat:@"%s:%d", __func__, __LINE__]];
@@ -398,9 +419,9 @@ RCT_EXPORT_METHOD(cartCleared) {
398
419
  }
399
420
  }
400
421
 
401
- RCT_EXPORT_METHOD(itemAddedToWishlist:(NSDictionary *)productMustMap productOptMap:(NSDictionary *)productOptMap) {
422
+ RCT_EXPORT_METHOD(itemAddedToWishlist:(NSDictionary *)requiredFields optionalFields:(NSDictionary *)optionalFields customParameters:(NSArray *)customParameters) {
402
423
  @try {
403
- InsiderProduct *product = [InsiderHybrid createProduct:productMustMap productOptMap:productOptMap];
424
+ InsiderProduct *product = [RNUtils parseProductFromRequiredFields:requiredFields andOptionalFields:optionalFields andCustomParameters:customParameters];
404
425
  [Insider itemAddedToWishlistWithProduct:product];
405
426
  } @catch (NSException *e){
406
427
  [Insider sendError:e desc:[NSString stringWithFormat:@"%s:%d", __func__, __LINE__]];
@@ -445,9 +466,9 @@ RCT_EXPORT_METHOD(getSmartRecommendation:(int)recommendationID locale:(NSString
445
466
  }
446
467
  }
447
468
 
448
- RCT_EXPORT_METHOD(getSmartRecommendationWithProduct:(NSDictionary *)productMustMap productOptMap:(NSDictionary *)productOptMap recommendationID:(int)recommendationID locale:(NSString *)locale smartRecommendation:(RCTResponseSenderBlock) smartRecommendation) {
469
+ RCT_EXPORT_METHOD(getSmartRecommendationWithProduct:(NSDictionary *)requiredFields optionalFields:(NSDictionary *)optionalFields customParameters:(NSArray *)customParameters recommendationID:(int)recommendationID locale:(NSString *)locale smartRecommendation:(RCTResponseSenderBlock) smartRecommendation) {
449
470
  @try {
450
- InsiderProduct *product = [InsiderHybrid createProduct:productMustMap productOptMap:productOptMap];
471
+ InsiderProduct *product = [RNUtils parseProductFromRequiredFields:requiredFields andOptionalFields:optionalFields andCustomParameters:customParameters];
451
472
  [Insider getSmartRecommendationWithProduct:product recommendationID:recommendationID locale:locale smartRecommendation:^(NSDictionary *recommendation) {
452
473
  smartRecommendation([NSArray arrayWithObject:recommendation]);
453
474
  }];
@@ -466,9 +487,9 @@ RCT_EXPORT_METHOD(getSmartRecommendationWithProductIDs:(NSArray *)productIDs rec
466
487
  }
467
488
  }
468
489
 
469
- RCT_EXPORT_METHOD(clickSmartRecommendationProduct:(int)recommendationID productMustMap:(NSDictionary *)productMustMap productOptMap:(NSDictionary *)productOptMap) {
490
+ RCT_EXPORT_METHOD(clickSmartRecommendationProduct:(int)recommendationID requiredFields:(NSDictionary *)requiredFields optionalFields:(NSDictionary *)optionalFields customParameters:(NSArray *)customParameters) {
470
491
  @try {
471
- InsiderProduct *product = [InsiderHybrid createProduct:productMustMap productOptMap:productOptMap];
492
+ InsiderProduct *product = [RNUtils parseProductFromRequiredFields:requiredFields andOptionalFields:optionalFields andCustomParameters:customParameters];
472
493
  [Insider clickSmartRecommendationProductWithID:recommendationID product:product];
473
494
  } @catch (NSException *e) {
474
495
  [Insider sendError:e desc:[NSString stringWithFormat:@"%s:%d", __func__, __LINE__]];
@@ -539,9 +560,9 @@ RCT_EXPORT_METHOD(visitListingPage:(NSArray *)taxonomy) {
539
560
  }
540
561
  }
541
562
 
542
- RCT_EXPORT_METHOD(visitProductDetailPage:(NSDictionary *)productMustMap productOptMap:(NSDictionary *)productOptMap) {
563
+ RCT_EXPORT_METHOD(visitProductDetailPage:(NSDictionary *)requiredFields optionalFields:(NSDictionary *)optionalFields customParameters:(NSArray *)customParameters) {
543
564
  @try {
544
- InsiderProduct *product = [InsiderHybrid createProduct:productMustMap productOptMap:productOptMap];
565
+ InsiderProduct *product = [RNUtils parseProductFromRequiredFields:requiredFields andOptionalFields:optionalFields andCustomParameters:customParameters];
545
566
  [Insider visitProductDetailPageWithProduct:product];
546
567
  } @catch (NSException *e) {
547
568
  [Insider sendError:e desc:[NSString stringWithFormat:@"%s:%d", __func__, __LINE__]];
@@ -550,7 +571,15 @@ RCT_EXPORT_METHOD(visitProductDetailPage:(NSDictionary *)productMustMap productO
550
571
 
551
572
  RCT_EXPORT_METHOD(visitCartPage:(NSArray *)products) {
552
573
  @try {
553
- [InsiderHybrid visitCartPage:products];
574
+ NSMutableArray<InsiderProduct *> *mappedProducts = [NSMutableArray array];
575
+ for (NSDictionary *productDict in products) {
576
+ NSDictionary *requiredFields = productDict[@"requiredFields"];
577
+ NSDictionary *optionalFields = productDict[@"optionalFields"];
578
+ NSArray *customParameters = productDict[@"customParameters"];
579
+ InsiderProduct *product = [RNUtils parseProductFromRequiredFields:requiredFields andOptionalFields:optionalFields andCustomParameters:customParameters];
580
+ [mappedProducts addObject:product];
581
+ }
582
+ [Insider visitCartPageWithProducts:[mappedProducts copy]];
554
583
  } @catch (NSException *e) {
555
584
  [Insider sendError:e desc:[NSString stringWithFormat:@"%s:%d", __func__, __LINE__]];
556
585
  }
@@ -558,7 +587,15 @@ RCT_EXPORT_METHOD(visitCartPage:(NSArray *)products) {
558
587
 
559
588
  RCT_EXPORT_METHOD(visitWishlistPage:(NSArray *)products) {
560
589
  @try {
561
- [InsiderHybrid convertArrayToInsiderProductArray:products];
590
+ NSMutableArray<InsiderProduct *> *mappedProducts = [NSMutableArray array];
591
+ for (NSDictionary *productDict in products) {
592
+ NSDictionary *requiredFields = productDict[@"requiredFields"];
593
+ NSDictionary *optionalFields = productDict[@"optionalFields"];
594
+ NSArray *customParameters = productDict[@"customParameters"];
595
+ InsiderProduct *product = [RNUtils parseProductFromRequiredFields:requiredFields andOptionalFields:optionalFields andCustomParameters:customParameters];
596
+ [mappedProducts addObject:product];
597
+ }
598
+ [Insider visitWishlistWithProducts:[mappedProducts copy]];
562
599
  } @catch (NSException *e) {
563
600
  [Insider sendError:e desc:[NSString stringWithFormat:@"%s:%d", __func__, __LINE__]];
564
601
  }
@@ -0,0 +1,26 @@
1
+ //
2
+ // RNUtils.h
3
+ // RNInsider
4
+ //
5
+ // Created by Heysem on 22.12.2025.
6
+ // Copyright © 2025 Insider. All rights reserved.
7
+ //
8
+
9
+ #import <Foundation/Foundation.h>
10
+
11
+ #if __has_include(<InsiderMobile/Insider.h>)
12
+ #import <InsiderMobile/Insider.h>
13
+ #elif __has_include("Insider.h")
14
+ #import "Insider.h"
15
+ #endif
16
+
17
+ @interface RNUtils : NSObject
18
+
19
+ + (nonnull InsiderEvent *)parseEventFromEventName:(nonnull NSString *)eventName
20
+ andParameters:(nullable NSArray *)parameters;
21
+
22
+ + (nonnull InsiderProduct *)parseProductFromRequiredFields:(nonnull NSDictionary *)requiredFields
23
+ andOptionalFields:(nullable NSDictionary *)optionalFields
24
+ andCustomParameters:(nullable NSArray *)customParameters;
25
+
26
+ @end
@@ -0,0 +1,250 @@
1
+ //
2
+ // RNUtils.m
3
+ // RNInsider
4
+ //
5
+ // Created by Heysem on 22.12.2025.
6
+ // Copyright © 2025 Insider. All rights reserved.
7
+ //
8
+
9
+ #import "RNUtils.h"
10
+
11
+ @implementation RNUtils
12
+
13
+ + (InsiderEvent *)parseEventFromEventName:(NSString *)eventName
14
+ andParameters:(NSArray *)parameters {
15
+
16
+ InsiderEvent *event = [Insider tagEvent:eventName];
17
+
18
+ if (![parameters isKindOfClass:[NSArray class]]) {
19
+ return event;
20
+ }
21
+
22
+ for (id item in parameters) {
23
+ if (![item isKindOfClass:[NSDictionary class]]) continue;
24
+
25
+ NSDictionary *parameter = (NSDictionary *)item;
26
+
27
+ NSString *type = parameter[@"type"];
28
+ NSString *key = parameter[@"key"];
29
+ if (![type isKindOfClass:[NSString class]] || ![key isKindOfClass:[NSString class]]) continue;
30
+
31
+ id value = parameter[@"value"];
32
+
33
+ if ([type isEqualToString:@"string"] && [value isKindOfClass:[NSString class]]) {
34
+ NSString *stringValue = value;
35
+ event.addParameterWithString(key, stringValue);
36
+ }
37
+ else if ([type isEqualToString:@"integer"] && [value isKindOfClass:[NSNumber class]]) {
38
+ NSNumber *numberValue = value;
39
+ int integerValue = (int)(numberValue != nil ? numberValue.integerValue : 0);
40
+ event.addParameterWithInt(key, integerValue);
41
+ }
42
+ else if ([type isEqualToString:@"double"] && [value isKindOfClass:[NSNumber class]]) {
43
+ NSNumber *numberValue = value;
44
+ double doubleValue = (numberValue != nil ? numberValue.doubleValue : 0.0);
45
+ event.addParameterWithDouble(key, doubleValue);
46
+ }
47
+ else if ([type isEqualToString:@"boolean"] && [value isKindOfClass:[NSNumber class]]) {
48
+ NSNumber *numberValue = value;
49
+ BOOL booleanValue = (numberValue != nil ? numberValue.boolValue : NO);
50
+ event.addParameterWithBoolean(key, booleanValue);
51
+ }
52
+ else if ([type isEqualToString:@"date"] && [value isKindOfClass:[NSString class]]) {
53
+ long long epochMillis = [(NSString *)value longLongValue];
54
+ NSTimeInterval seconds = ((NSTimeInterval)epochMillis) / 1000.0;
55
+ NSDate *dateValue = [NSDate dateWithTimeIntervalSince1970:seconds];
56
+ event.addParameterWithDate(key, dateValue);
57
+ }
58
+ else if ([type isEqualToString:@"strings"] && [value isKindOfClass:[NSArray class]]) {
59
+ NSArray * stringsValue = value;
60
+ event.addParameterWithStringArray(key, stringsValue);
61
+ }
62
+ else if ([type isEqualToString:@"numbers"] && [value isKindOfClass:[NSArray class]]) {
63
+ NSArray * numbersValue = value;
64
+ event.addParameterWithNumericArray(key, numbersValue);
65
+ }
66
+ else {
67
+ @throw [NSException exceptionWithName:NSInvalidArgumentException
68
+ reason:@"Unknown parameter type received."
69
+ userInfo:@{ @"type": type ?: @"(null)" }];
70
+ }
71
+ }
72
+
73
+ return event;
74
+ }
75
+
76
+ + (nonnull InsiderProduct *)parseProductFromRequiredFields:(nonnull NSDictionary *)requiredFields
77
+ andOptionalFields:(nullable NSDictionary *)optionalFields
78
+ andCustomParameters:(nullable NSArray *)customParameters {
79
+
80
+ /// Apply required fields
81
+ NSString *productId = requiredFields[@"product_id"];
82
+ NSString *name = requiredFields[@"name"];
83
+ NSArray *taxonomy = requiredFields[@"taxonomy"];
84
+ NSString *imageURL = requiredFields[@"image_url"];
85
+ NSNumber *priceNumber = requiredFields[@"price"];
86
+ double price = [priceNumber isKindOfClass:[NSNumber class]] ? priceNumber.doubleValue : 0.0;
87
+ NSString *currency = requiredFields[@"currency"];
88
+
89
+ InsiderProduct *product = [Insider createNewProductWithID:productId name:name taxonomy:taxonomy imageURL:imageURL price:price currency:currency];
90
+
91
+ /// Apply optional fields
92
+ for (NSString *key in optionalFields) {
93
+ id value = optionalFields[key];
94
+
95
+ if ([key isEqualToString:@"color"]) {
96
+ NSString *color = (NSString *)value;
97
+ product.setColor(color);
98
+ }
99
+ else if ([key isEqualToString:@"voucher_name"]) {
100
+ NSString *voucherName = (NSString *)value;
101
+ product.setVoucherName(voucherName);
102
+ }
103
+ else if ([key isEqualToString:@"promotion_name"]) {
104
+ NSString *promotionName = (NSString *)value;
105
+ product.setPromotionName(promotionName);
106
+ }
107
+ else if ([key isEqualToString:@"size"]) {
108
+ NSString *size = (NSString *)value;
109
+ product.setSize(size);
110
+ }
111
+ else if ([key isEqualToString:@"sale_price"]) {
112
+ NSNumber *salePriceNumber = (NSNumber *)value;
113
+ double salePrice = salePriceNumber.doubleValue;
114
+ product.setSalePrice(salePrice);
115
+ }
116
+ else if ([key isEqualToString:@"shipping_cost"]) {
117
+ NSNumber *shippingCostNumber = (NSNumber *)value;
118
+ double shippingCost = shippingCostNumber.doubleValue;
119
+ product.setShippingCost(shippingCost);
120
+ }
121
+ else if ([key isEqualToString:@"voucher_discount"]) {
122
+ NSNumber *voucherDiscountNumber = (NSNumber *)value;
123
+ double voucherDiscount = voucherDiscountNumber.doubleValue;
124
+ product.setVoucherDiscount(voucherDiscount);
125
+ }
126
+ else if ([key isEqualToString:@"promotion_discount"]) {
127
+ NSNumber *promotionDiscountNumber = (NSNumber *)value;
128
+ double promotionDiscount = promotionDiscountNumber.doubleValue;
129
+ product.setPromotionDiscount(promotionDiscount);
130
+ }
131
+ else if ([key isEqualToString:@"stock"]) {
132
+ NSNumber *stockNumber = (NSNumber *)value;
133
+ int stock = stockNumber.intValue;
134
+ product.setStock(stock);
135
+ }
136
+ else if ([key isEqualToString:@"quantity"]) {
137
+ NSNumber *quantityNumber = (NSNumber *)value;
138
+ int quantity = quantityNumber.intValue;
139
+ product.setQuantity(quantity);
140
+ }
141
+ else if ([key isEqualToString:@"group_code"]) {
142
+ NSString *groupCode = (NSString *)value;
143
+ product.setGroupCode(groupCode);
144
+ }
145
+ else if ([key isEqualToString:@"brand"]) {
146
+ NSString *brand = (NSString *)value;
147
+ product.setBrand(brand);
148
+ }
149
+ else if ([key isEqualToString:@"sku"]) {
150
+ NSString *sku = (NSString *)value;
151
+ product.setSku(sku);
152
+ }
153
+ else if ([key isEqualToString:@"gender"]) {
154
+ NSString *gender = (NSString *)value;
155
+ product.setGender(gender);
156
+ }
157
+ else if ([key isEqualToString:@"multipack"]) {
158
+ NSString *multipack = (NSString *)value;
159
+ product.setMultipack(multipack);
160
+ }
161
+ else if ([key isEqualToString:@"product_type"]) {
162
+ NSString *productType = (NSString *)value;
163
+ product.setProductType(productType);
164
+ }
165
+ else if ([key isEqualToString:@"gtin"]) {
166
+ NSString *gtin = (NSString *)value;
167
+ product.setGtin(gtin);
168
+ }
169
+ else if ([key isEqualToString:@"description"]) {
170
+ NSString *desc = (NSString *)value;
171
+ product.setDescription(desc);
172
+ }
173
+ else if ([key isEqualToString:@"tags"]) {
174
+ NSArray *tagsArray = (NSArray *)value;
175
+ product.setTags(tagsArray);
176
+ }
177
+ else if ([key isEqualToString:@"in_stock"]) {
178
+ NSNumber *inStockNumber = (NSNumber *)value;
179
+ BOOL inStock = inStockNumber.boolValue;
180
+ product.setInStock(inStock);
181
+ }
182
+ else if ([key isEqualToString:@"product_url"]) {
183
+ NSString *productURL = (NSString *)value;
184
+ product.setProductURL(productURL);
185
+ } else {
186
+ NSLog(@"WTF");
187
+ }
188
+ }
189
+
190
+ /// Apply custom parameters
191
+ for (id item in customParameters) {
192
+ if (![item isKindOfClass:[NSDictionary class]]) continue;
193
+
194
+ NSDictionary *parameter = (NSDictionary *)item;
195
+
196
+ NSString *type = parameter[@"type"];
197
+ NSString *key = parameter[@"key"];
198
+ if (![type isKindOfClass:[NSString class]] || ![key isKindOfClass:[NSString class]]) continue;
199
+
200
+ id value = parameter[@"value"];
201
+
202
+ if ([type isEqualToString:@"string"] && [value isKindOfClass:[NSString class]]) {
203
+ NSString *stringValue = (NSString *)value;
204
+ product.setCustomAttributeWithString(key, stringValue);
205
+ }
206
+ else if ([type isEqualToString:@"integer"] && [value isKindOfClass:[NSNumber class]]) {
207
+ NSNumber *numberValue = (NSNumber *)value;
208
+ int intValue = (int)numberValue.integerValue;
209
+ product.setCustomAttributeWithInt(key, intValue);
210
+ }
211
+ else if ([type isEqualToString:@"double"] && [value isKindOfClass:[NSNumber class]]) {
212
+ NSNumber *numberValue = (NSNumber *)value;
213
+ double doubleValue = numberValue.doubleValue;
214
+ product.setCustomAttributeWithDouble(key, doubleValue);
215
+ }
216
+ else if ([type isEqualToString:@"boolean"] && [value isKindOfClass:[NSNumber class]]) {
217
+ NSNumber *numberValue = (NSNumber *)value;
218
+ BOOL booleanValue = numberValue.boolValue;
219
+ product.setCustomAttributeWithBoolean(key, booleanValue);
220
+ }
221
+ else if ([type isEqualToString:@"date"] && [value isKindOfClass:[NSString class]]) {
222
+ // Epoch millis passed as string from RN
223
+ NSString *epochString = (NSString *)value;
224
+ long long epochMillis = epochString.longLongValue;
225
+ NSTimeInterval seconds = ((NSTimeInterval)epochMillis) / 1000.0;
226
+ NSDate *dateValue = [NSDate dateWithTimeIntervalSince1970:seconds];
227
+ product.setCustomAttributeWithDate(key, dateValue);
228
+ }
229
+ else if ([type isEqualToString:@"strings"] && [value isKindOfClass:[NSArray class]]) {
230
+ NSArray *stringsValue = (NSArray *)value;
231
+ product.setCustomAttributeWithStringArray(key, stringsValue);
232
+ }
233
+ else if ([type isEqualToString:@"numbers"] && [value isKindOfClass:[NSArray class]]) {
234
+ NSArray *numbersValue = (NSArray *)value;
235
+ product.setCustomAttributeWithNumericArray(key, numbersValue);
236
+ }
237
+ else {
238
+ @throw [NSException exceptionWithName:NSInvalidArgumentException
239
+ reason:@"Unknown parameter type received."
240
+ userInfo:@{
241
+ @"type": type ?: @"(null)",
242
+ @"key": key ?: @"(null)"
243
+ }];
244
+ }
245
+ }
246
+
247
+ return product;
248
+ }
249
+
250
+ @end
@@ -9,6 +9,7 @@
9
9
  /* Begin PBXBuildFile section */
10
10
  2C9AFE602271DF87004B96DF /* RNNotificationHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C9AFE5F2271DF87004B96DF /* RNNotificationHandler.m */; };
11
11
  B3E7B58A1CC2AC0600A0062D /* RNInsider.m in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* RNInsider.m */; };
12
+ B675CCA92EF9527D005D3A3C /* RNUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = B675CCA82EF9527C005D3A3C /* RNUtils.m */; };
12
13
  /* End PBXBuildFile section */
13
14
 
14
15
  /* Begin PBXCopyFilesBuildPhase section */
@@ -29,6 +30,8 @@
29
30
  2C9AFE5F2271DF87004B96DF /* RNNotificationHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNotificationHandler.m; sourceTree = "<group>"; };
30
31
  B3E7B5881CC2AC0600A0062D /* RNInsider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNInsider.h; sourceTree = "<group>"; };
31
32
  B3E7B5891CC2AC0600A0062D /* RNInsider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNInsider.m; sourceTree = "<group>"; };
33
+ B675CCA72EF9526E005D3A3C /* RNUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNUtils.h; sourceTree = "<group>"; };
34
+ B675CCA82EF9527C005D3A3C /* RNUtils.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNUtils.m; sourceTree = "<group>"; };
32
35
  /* End PBXFileReference section */
33
36
 
34
37
  /* Begin PBXFrameworksBuildPhase section */
@@ -57,6 +60,8 @@
57
60
  2C9AFE5F2271DF87004B96DF /* RNNotificationHandler.m */,
58
61
  B3E7B5881CC2AC0600A0062D /* RNInsider.h */,
59
62
  B3E7B5891CC2AC0600A0062D /* RNInsider.m */,
63
+ B675CCA72EF9526E005D3A3C /* RNUtils.h */,
64
+ B675CCA82EF9527C005D3A3C /* RNUtils.m */,
60
65
  );
61
66
  path = RNInsider;
62
67
  sourceTree = "<group>";
@@ -136,6 +141,7 @@
136
141
  files = (
137
142
  B3E7B58A1CC2AC0600A0062D /* RNInsider.m in Sources */,
138
143
  2C9AFE602271DF87004B96DF /* RNNotificationHandler.m in Sources */,
144
+ B675CCA92EF9527D005D3A3C /* RNUtils.m in Sources */,
139
145
  );
140
146
  runOnlyForDeploymentPostprocessing = 0;
141
147
  };
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>SchemeUserState</key>
6
+ <dict>
7
+ <key>RNInsider.xcscheme_^#shared#^_</key>
8
+ <dict>
9
+ <key>orderHint</key>
10
+ <integer>0</integer>
11
+ </dict>
12
+ </dict>
13
+ </dict>
14
+ </plist>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <Bucket
3
+ uuid = "A1F4F672-C853-4C1A-95C2-4792BDA46408"
4
+ type = "1"
5
+ version = "2.0">
6
+ </Bucket>
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>SchemeUserState</key>
6
+ <dict>
7
+ <key>RNInsider.xcscheme_^#shared#^_</key>
8
+ <dict>
9
+ <key>orderHint</key>
10
+ <integer>0</integer>
11
+ </dict>
12
+ </dict>
13
+ </dict>
14
+ </plist>