Skip to content

Commit 0af48f4

Browse files
Refactoring. Separate out Serialization.
1 parent ee27f7e commit 0af48f4

File tree

3 files changed

+152
-145
lines changed

3 files changed

+152
-145
lines changed

ios/RNIterableAPI/RNIterableAPI.m

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,13 @@ @interface RCT_EXTERN_REMAP_MODULE(RNIterableAPI, ReactIterableAPI, NSObject)
3939
RCT_EXTERN_METHOD(trackPushOpenWithPayload: (NSDictionary *) payload
4040
dataFields: (NSDictionary *) dataFields)
4141

42-
RCT_EXTERN_METHOD(trackPushOpenWithCampaignId: (NSNumber) campaignId
43-
templateId: (NSNumber) templateId
42+
RCT_EXTERN_METHOD(trackPushOpenWithCampaignId: (nonnull NSNumber *) campaignId
43+
templateId: (nonnull NSNumber *) templateId
4444
messageId: (NSString *) messageId
4545
appAlreadyRunning: (BOOL) appAlreadyRunning
4646
dataFields: (NSDictionary *) dataFields)
4747

48-
RCT_EXTERN_METHOD(trackPurchaseWithTotal: (NSNumber) total
48+
RCT_EXTERN_METHOD(trackPurchaseWithTotal: (nonnull NSNumber *) total
4949
items: (NSArray *) items
5050
dataFields: (NSDictionary *) dataFields)
5151

ios/RNIterableAPI/ReactIterableAPI.swift

Lines changed: 6 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class ReactIterableAPI: RCTEventEmitter {
4949
func initialize(apiKey: String, config configDict: [AnyHashable: Any]) {
5050
ITBInfo()
5151
let launchOptions = createLaunchOptions()
52-
let iterableConfig = ReactIterableAPI.createIterableConfig(from: configDict)
52+
let iterableConfig = IterableConfig.from(dict: configDict)
5353
if let urlDelegatePresent = configDict["urlDelegatePresent"] as? Bool, urlDelegatePresent == true {
5454
iterableConfig.urlDelegate = self
5555
}
@@ -59,9 +59,6 @@ class ReactIterableAPI: RCTEventEmitter {
5959
if let inAppDelegatePresent = configDict["inAppDelegatePresent"] as? Bool, inAppDelegatePresent == true {
6060
iterableConfig.inAppDelegate = self
6161
}
62-
if let inAppDisplayInterval = configDict["inAppDisplayInterval"] as? Double {
63-
iterableConfig.inAppDisplayInterval = inAppDisplayInterval
64-
}
6562

6663
DispatchQueue.main.async {
6764
IterableAPI.initialize(apiKey: apiKey, launchOptions: launchOptions, config: iterableConfig)
@@ -136,7 +133,7 @@ class ReactIterableAPI: RCTEventEmitter {
136133
return
137134
}
138135

139-
resolver(attributionInfo.toDictionary())
136+
resolver(SerializationUtil.encodableToDictionary(encodable: attributionInfo))
140137
}
141138

142139
@objc(setAttributionInfo:)
@@ -147,7 +144,7 @@ class ReactIterableAPI: RCTEventEmitter {
147144
return
148145
}
149146

150-
IterableAPI.attributionInfo = dict.toDecodable()
147+
IterableAPI.attributionInfo = SerializationUtil.dictionaryToDecodable(dict: dict)
151148
}
152149

153150
@objc(trackPushOpenWithPayload:dataFields:)
@@ -172,14 +169,14 @@ class ReactIterableAPI: RCTEventEmitter {
172169
dataFields: [AnyHashable: Any]?) {
173170
ITBInfo()
174171
IterableAPI.track(purchase: total,
175-
items: items.compactMap(ReactIterableAPI.dictionaryToCommerceItem),
172+
items: items.compactMap(CommerceItem.from(dict:)),
176173
dataFields: dataFields)
177174
}
178175

179176
@objc(getInAppMessages:rejecter:)
180177
func getInAppMessages(resolver: RCTPromiseResolveBlock, rejecter: RCTPromiseRejectBlock) {
181178
ITBInfo()
182-
resolver(IterableAPI.inAppManager.getMessages().map{ ReactIterableAPI.inAppMessageToDict(message: $0) })
179+
resolver(IterableAPI.inAppManager.getMessages().map{ $0.toDict() })
183180
}
184181

185182
@objc(trackEvent:)
@@ -217,101 +214,6 @@ class ReactIterableAPI: RCTEventEmitter {
217214
result[UIApplication.LaunchOptionsKey.remoteNotification] = remoteNotification
218215
return result
219216
}
220-
221-
private static func createIterableConfig(from dict: [AnyHashable: Any]?) -> IterableConfig {
222-
let config = IterableConfig()
223-
guard let dict = dict else {
224-
return config
225-
}
226-
227-
if let pushIntegrationName = dict["pushIntegrationName"] as? String {
228-
config.pushIntegrationName = pushIntegrationName
229-
}
230-
if let sandboxPushIntegrationName = dict["sandboxPushIntegrationName"] as? String {
231-
config.sandboxPushIntegrationName = sandboxPushIntegrationName
232-
}
233-
if let intValue = dict["pushPlatform"] as? Int, let pushPlatform = PushServicePlatform(rawValue: intValue) {
234-
config.pushPlatform = pushPlatform
235-
}
236-
if let autoPushRegistration = dict["autoPushRegistration"] as? Bool {
237-
config.autoPushRegistration = autoPushRegistration
238-
}
239-
if let checkForDeferredDeeplink = dict["checkForDeferredDeeplink"] as? Bool {
240-
config.checkForDeferredDeeplink = checkForDeferredDeeplink
241-
}
242-
243-
return config
244-
}
245-
246-
private static func dictionaryToCommerceItem(dict: [AnyHashable: Any]) -> CommerceItem? {
247-
guard let id = dict["id"] as? String else {
248-
return nil
249-
}
250-
guard let name = dict["name"] as? String else {
251-
return nil
252-
}
253-
guard let price = dict["price"] as? NSNumber else {
254-
return nil
255-
}
256-
guard let quantity = dict["quantity"] as? UInt else {
257-
return nil
258-
}
259-
260-
return CommerceItem(id: id, name: name, price: price, quantity: quantity)
261-
}
262-
263-
private static func inAppTriggerToDict(trigger: IterableInAppTrigger) -> [AnyHashable: Any] {
264-
var dict = [AnyHashable: Any]()
265-
dict["type"] = trigger.type.rawValue
266-
return dict
267-
}
268-
269-
private static func edgeInsetsToDict(edgeInsets: UIEdgeInsets) -> [AnyHashable: Any] {
270-
var dict = [AnyHashable: Any]()
271-
dict["top"] = edgeInsets.top
272-
dict["left"] = edgeInsets.left
273-
dict["bottom"] = edgeInsets.bottom
274-
dict["right"] = edgeInsets.right
275-
return dict
276-
}
277-
278-
private static func inAppMessageToDict(message: IterableInAppMessage) -> [AnyHashable: Any] {
279-
var dict = [AnyHashable: Any]()
280-
dict["messageId"] = message.messageId
281-
dict["campaignId"] = message.campaignId
282-
dict["trigger"] = inAppTriggerToDict(trigger: message.trigger)
283-
dict["createdAt"] = message.createdAt.map { $0.iterableIntValue }
284-
dict["expiresAt"] = message.expiresAt.map { $0.iterableIntValue }
285-
dict["saveToInbox"] = message.saveToInbox
286-
dict["inboxMetadata"] = inboxMetadataToDict(metadata: message.inboxMetadata)
287-
dict["customPayload"] = message.customPayload
288-
dict["read"] = message.read
289-
return dict
290-
}
291-
292-
private static func inAppContentToDict(content: IterableInAppContent) -> [AnyHashable: Any] {
293-
guard let htmlInAppContent = content as? IterableHtmlInAppContent else {
294-
return [:]
295-
}
296-
297-
var dict = [AnyHashable: Any]()
298-
dict["type"] = htmlInAppContent.type.rawValue
299-
dict["edgeInsets"] = edgeInsetsToDict(edgeInsets: htmlInAppContent.edgeInsets)
300-
dict["backgroundAlpha"] = htmlInAppContent.backgroundAlpha
301-
dict["html"] = htmlInAppContent.html
302-
return dict
303-
}
304-
305-
private static func inboxMetadataToDict(metadata: IterableInboxMetadata?) -> [AnyHashable: Any]? {
306-
guard let metadata = metadata else {
307-
return nil
308-
}
309-
var dict = [AnyHashable: Any]()
310-
dict["title"] = metadata.title
311-
dict["subtitle"] = metadata.subtitle
312-
dict["icon"] = metadata.icon
313-
return dict
314-
}
315217
}
316218

317219
extension ReactIterableAPI: IterableURLDelegate {
@@ -372,7 +274,7 @@ extension ReactIterableAPI: IterableInAppDelegate {
372274
return .show
373275
}
374276

375-
let messageDict = ReactIterableAPI.inAppMessageToDict(message: message)
277+
let messageDict = message.toDict()
376278
sendEvent(withName: EventName.handleInAppCalled.rawValue, body: messageDict)
377279
let timeoutResult = inAppDelegateSemapohore.wait(timeout: .now() + 2.0)
378280

@@ -386,41 +288,3 @@ extension ReactIterableAPI: IterableInAppDelegate {
386288
}
387289
}
388290

389-
// TODO: make public
390-
extension Encodable {
391-
public func toDictionary() -> [String: Any]? {
392-
guard let data = try? JSONEncoder().encode(self) else {
393-
return nil
394-
}
395-
396-
return try? JSONSerialization.jsonObject(with: data, options: [.allowFragments]) as? [String: Any]
397-
}
398-
}
399-
400-
// TODO: make public
401-
extension Dictionary where Key == AnyHashable, Value == Any {
402-
public func toDecodable<T>() -> T? where T: Decodable {
403-
guard let data = try? JSONSerialization.data(withJSONObject: self, options: []) else {
404-
return nil
405-
}
406-
407-
return try? JSONDecoder().decode(T.self, from: data)
408-
409-
}
410-
}
411-
412-
// TODO: make public
413-
extension Date {
414-
public var iterableIntValue: Int {
415-
return Int(self.timeIntervalSince1970 * 1000)
416-
}
417-
}
418-
419-
// TODO: make public
420-
extension Int {
421-
public var iterableDateValue: Date {
422-
let seconds = Double(self) / 1000.0 // ms -> seconds
423-
424-
return Date(timeIntervalSince1970: seconds)
425-
}
426-
}
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
//
2+
// Created by Tapash Majumder on 3/19/20.
3+
// Copyright © 2020 Iterable. All rights reserved.
4+
//
5+
6+
import Foundation
7+
8+
import IterableSDK;
9+
10+
struct SerializationUtil {
11+
static func dateToInt(date: Date) -> Int {
12+
Int(date.timeIntervalSince1970 * 1000)
13+
}
14+
15+
static func intToDate(int: Int) -> Date {
16+
let seconds = Double(int) / 1000.0 // ms -> seconds
17+
18+
return Date(timeIntervalSince1970: seconds)
19+
}
20+
21+
static func encodableToDictionary<T>(encodable: T) -> [String: Any]? where T: Encodable {
22+
guard let data = try? JSONEncoder().encode(encodable) else {
23+
return nil
24+
}
25+
26+
return try? JSONSerialization.jsonObject(with: data, options: [.allowFragments]) as? [String: Any]
27+
}
28+
29+
static func dictionaryToDecodable<T>(dict: [AnyHashable: Any]) -> T? where T: Decodable {
30+
guard let data = try? JSONSerialization.data(withJSONObject: dict, options: []) else {
31+
return nil
32+
}
33+
34+
return try? JSONDecoder().decode(T.self, from: data)
35+
}
36+
37+
static func inAppContentToDict(content: IterableInAppContent) -> [AnyHashable: Any] {
38+
guard let htmlInAppContent = content as? IterableHtmlInAppContent else {
39+
return [:]
40+
}
41+
42+
var dict = [AnyHashable: Any]()
43+
dict["type"] = htmlInAppContent.type.rawValue
44+
dict["edgeInsets"] = htmlInAppContent.edgeInsets.toDict()
45+
dict["backgroundAlpha"] = htmlInAppContent.backgroundAlpha
46+
dict["html"] = htmlInAppContent.html
47+
return dict
48+
}
49+
}
50+
51+
extension IterableConfig {
52+
static func from(dict: [AnyHashable: Any]?) -> IterableConfig {
53+
let config = IterableConfig()
54+
guard let dict = dict else {
55+
return config
56+
}
57+
58+
if let pushIntegrationName = dict["pushIntegrationName"] as? String {
59+
config.pushIntegrationName = pushIntegrationName
60+
}
61+
if let sandboxPushIntegrationName = dict["sandboxPushIntegrationName"] as? String {
62+
config.sandboxPushIntegrationName = sandboxPushIntegrationName
63+
}
64+
if let intValue = dict["pushPlatform"] as? Int, let pushPlatform = PushServicePlatform(rawValue: intValue) {
65+
config.pushPlatform = pushPlatform
66+
}
67+
if let autoPushRegistration = dict["autoPushRegistration"] as? Bool {
68+
config.autoPushRegistration = autoPushRegistration
69+
}
70+
if let checkForDeferredDeeplink = dict["checkForDeferredDeeplink"] as? Bool {
71+
config.checkForDeferredDeeplink = checkForDeferredDeeplink
72+
}
73+
if let inAppDisplayInterval = dict["inAppDisplayInterval"] as? Double {
74+
config.inAppDisplayInterval = inAppDisplayInterval
75+
}
76+
77+
return config
78+
}
79+
}
80+
81+
extension CommerceItem {
82+
static func from(dict: [AnyHashable: Any]) -> CommerceItem? {
83+
guard let id = dict["id"] as? String else {
84+
return nil
85+
}
86+
guard let name = dict["name"] as? String else {
87+
return nil
88+
}
89+
guard let price = dict["price"] as? NSNumber else {
90+
return nil
91+
}
92+
guard let quantity = dict["quantity"] as? UInt else {
93+
return nil
94+
}
95+
96+
return CommerceItem(id: id, name: name, price: price, quantity: quantity)
97+
}
98+
}
99+
100+
extension IterableInAppTrigger {
101+
func toDict() -> [AnyHashable: Any] {
102+
var dict = [AnyHashable: Any]()
103+
dict["type"] = self.type.rawValue
104+
return dict
105+
}
106+
}
107+
108+
extension UIEdgeInsets {
109+
func toDict() -> [AnyHashable: Any] {
110+
var dict = [AnyHashable: Any]()
111+
dict["top"] = top
112+
dict["left"] = left
113+
dict["bottom"] = bottom
114+
dict["right"] = right
115+
return dict
116+
}
117+
}
118+
119+
extension IterableInboxMetadata {
120+
func toDict() -> [AnyHashable: Any]? {
121+
var dict = [AnyHashable: Any]()
122+
dict["title"] = title
123+
dict["subtitle"] = subtitle
124+
dict["icon"] = icon
125+
return dict
126+
}
127+
}
128+
129+
extension IterableInAppMessage {
130+
func toDict() -> [AnyHashable: Any] {
131+
var dict = [AnyHashable: Any]()
132+
dict["messageId"] = messageId
133+
dict["campaignId"] = campaignId
134+
dict["trigger"] = trigger.toDict()
135+
dict["createdAt"] = createdAt.map (SerializationUtil.dateToInt(date:))
136+
dict["expiresAt"] = expiresAt.map (SerializationUtil.dateToInt(date:))
137+
dict["saveToInbox"] = saveToInbox
138+
dict["inboxMetadata"] = inboxMetadata?.toDict() ?? nil
139+
dict["customPayload"] = customPayload
140+
dict["read"] = read
141+
return dict
142+
}
143+
}

0 commit comments

Comments
 (0)