@digia-engage/core 2.3.2 → 2.4.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/DigiaEngageReactNative.podspec +1 -1
- package/android/.project +28 -0
- package/android/build.gradle +1 -1
- package/android/local.properties +1 -0
- package/android/src/main/java/com/digia/engage/rn/DigiaModule.kt +64 -6
- package/ios/DigiaModule.swift +70 -8
- package/ios/RNEventBridgePlugin.swift +2 -0
- package/lib/commonjs/Digia.js +139 -100
- package/lib/commonjs/Digia.js.map +1 -1
- package/lib/commonjs/DigiaAnchorView.js +11 -1
- package/lib/commonjs/DigiaAnchorView.js.map +1 -1
- package/lib/commonjs/DigiaProvider.js +63 -2
- package/lib/commonjs/DigiaProvider.js.map +1 -1
- package/lib/commonjs/NativeDigiaEngage.js +3 -0
- package/lib/commonjs/NativeDigiaEngage.js.map +1 -1
- package/lib/commonjs/digiaAnchorRegistry.js +3 -1
- package/lib/commonjs/digiaAnchorRegistry.js.map +1 -1
- package/lib/commonjs/frequencyStore.js +3 -3
- package/lib/commonjs/frequencyStore.js.map +1 -1
- package/lib/commonjs/index.js +0 -7
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/Digia.js +139 -100
- package/lib/module/Digia.js.map +1 -1
- package/lib/module/DigiaAnchorView.js +11 -1
- package/lib/module/DigiaAnchorView.js.map +1 -1
- package/lib/module/DigiaProvider.js +65 -3
- package/lib/module/DigiaProvider.js.map +1 -1
- package/lib/module/NativeDigiaEngage.js +3 -0
- package/lib/module/NativeDigiaEngage.js.map +1 -1
- package/lib/module/digiaAnchorRegistry.js +3 -1
- package/lib/module/digiaAnchorRegistry.js.map +1 -1
- package/lib/module/frequencyStore.js +3 -3
- package/lib/module/frequencyStore.js.map +1 -1
- package/lib/module/index.js +4 -4
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/Digia.d.ts +17 -8
- package/lib/typescript/Digia.d.ts.map +1 -1
- package/lib/typescript/DigiaAnchorView.d.ts.map +1 -1
- package/lib/typescript/DigiaProvider.d.ts +3 -1
- package/lib/typescript/DigiaProvider.d.ts.map +1 -1
- package/lib/typescript/NativeDigiaEngage.d.ts +9 -0
- package/lib/typescript/NativeDigiaEngage.d.ts.map +1 -1
- package/lib/typescript/digiaAnchorRegistry.d.ts +1 -0
- package/lib/typescript/digiaAnchorRegistry.d.ts.map +1 -1
- package/lib/typescript/frequencyStore.d.ts +1 -1
- package/lib/typescript/frequencyStore.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +5 -5
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/templateTypes.d.ts +24 -1
- package/lib/typescript/templateTypes.d.ts.map +1 -1
- package/lib/typescript/types.d.ts +17 -13
- package/lib/typescript/types.d.ts.map +1 -1
- package/package.json +8 -9
- package/src/Digia.ts +142 -114
- package/src/DigiaAnchorView.tsx +6 -1
- package/src/DigiaProvider.tsx +76 -2
- package/src/NativeDigiaEngage.ts +20 -0
- package/src/digiaAnchorRegistry.ts +3 -1
- package/src/frequencyStore.ts +4 -4
- package/src/index.ts +5 -5
- package/src/templateTypes.ts +31 -1
- package/src/types.ts +17 -13
|
@@ -28,7 +28,7 @@ Pod::Spec.new do |s|
|
|
|
28
28
|
s.dependency 'React-Core'
|
|
29
29
|
|
|
30
30
|
# ── Digia Engage iOS SDK ──────────────────────────────────────────────────
|
|
31
|
-
s.dependency 'DigiaEngage','~> 2.
|
|
31
|
+
s.dependency 'DigiaEngage','~> 2.4.0'
|
|
32
32
|
|
|
33
33
|
# ── New Architecture (Fabric / TurboModules) support ─────────────────────
|
|
34
34
|
install_modules_dependencies(s)
|
package/android/.project
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<projectDescription>
|
|
3
|
+
<name>digia-engage_core</name>
|
|
4
|
+
<comment>Project digia-engage_core created by Buildship.</comment>
|
|
5
|
+
<projects>
|
|
6
|
+
</projects>
|
|
7
|
+
<buildSpec>
|
|
8
|
+
<buildCommand>
|
|
9
|
+
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
|
|
10
|
+
<arguments>
|
|
11
|
+
</arguments>
|
|
12
|
+
</buildCommand>
|
|
13
|
+
</buildSpec>
|
|
14
|
+
<natures>
|
|
15
|
+
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
|
|
16
|
+
</natures>
|
|
17
|
+
<filteredResources>
|
|
18
|
+
<filter>
|
|
19
|
+
<id>1780322402778</id>
|
|
20
|
+
<name></name>
|
|
21
|
+
<type>30</type>
|
|
22
|
+
<matcher>
|
|
23
|
+
<id>org.eclipse.core.resources.regexFilterMatcher</id>
|
|
24
|
+
<arguments>node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
|
|
25
|
+
</matcher>
|
|
26
|
+
</filter>
|
|
27
|
+
</filteredResources>
|
|
28
|
+
</projectDescription>
|
package/android/build.gradle
CHANGED
|
@@ -71,7 +71,7 @@ android {
|
|
|
71
71
|
|
|
72
72
|
dependencies {
|
|
73
73
|
// Digia Engage Android library
|
|
74
|
-
implementation 'tech.digia:engage:2.
|
|
74
|
+
implementation 'tech.digia:engage:2.2.0'
|
|
75
75
|
|
|
76
76
|
// ── React Native ─────────────────────────────────────────────────────────
|
|
77
77
|
// React Native is provided by the host app; mark as compileOnly so it is
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
sdk.dir=/Users/ram/Library/Android/sdk
|
|
@@ -29,6 +29,7 @@ import androidx.lifecycle.setViewTreeLifecycleOwner
|
|
|
29
29
|
import androidx.lifecycle.setViewTreeViewModelStoreOwner
|
|
30
30
|
import androidx.savedstate.SavedStateRegistryOwner
|
|
31
31
|
import androidx.savedstate.setViewTreeSavedStateRegistryOwner
|
|
32
|
+
import com.digia.engage.CEPTriggerPayload
|
|
32
33
|
import com.digia.engage.DiagnosticReport
|
|
33
34
|
import com.digia.engage.Digia
|
|
34
35
|
import com.digia.engage.DigiaCEPDelegate
|
|
@@ -126,6 +127,54 @@ internal class DigiaModule(
|
|
|
126
127
|
Digia.setCurrentScreen(name)
|
|
127
128
|
}
|
|
128
129
|
|
|
130
|
+
// ─── Analytics identity ───────────────────────────────────────────────────
|
|
131
|
+
|
|
132
|
+
@ReactMethod
|
|
133
|
+
fun setUserId(userId: String) {
|
|
134
|
+
Digia.setUserId(userId)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
@ReactMethod
|
|
138
|
+
fun clearUserId() {
|
|
139
|
+
Digia.clearUserId()
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// ─── Analytics event forwarding (guide / JS-rendered campaigns) ───────────
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Records an analytics event originating from JS-rendered campaigns (guides).
|
|
146
|
+
* Native campaigns (nudge, inline, survey) are tracked internally by the SDK.
|
|
147
|
+
*/
|
|
148
|
+
@ReactMethod
|
|
149
|
+
fun trackEvent(
|
|
150
|
+
eventType: String,
|
|
151
|
+
campaignId: String,
|
|
152
|
+
campaignKey: String,
|
|
153
|
+
campaignType: String,
|
|
154
|
+
elementId: String?,
|
|
155
|
+
) {
|
|
156
|
+
android.util.Log.d("DigiaAnalytics", "[trackEvent] RN bridge received: type=$eventType campaignId=$campaignId campaignKey=$campaignKey campaignType=$campaignType elementId=$elementId")
|
|
157
|
+
val event = when (eventType) {
|
|
158
|
+
"impressed" -> DigiaExperienceEvent.Impressed
|
|
159
|
+
"clicked" -> DigiaExperienceEvent.Clicked(elementId)
|
|
160
|
+
"dismissed" -> DigiaExperienceEvent.Dismissed
|
|
161
|
+
else -> {
|
|
162
|
+
android.util.Log.w("DigiaAnalytics", "[trackEvent] unknown eventType='$eventType' — dropped")
|
|
163
|
+
return
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
val payload = InAppPayload(
|
|
167
|
+
id = campaignKey,
|
|
168
|
+
content = mapOf(
|
|
169
|
+
"campaign_id" to campaignId,
|
|
170
|
+
"campaign_key" to campaignKey,
|
|
171
|
+
"campaign_type" to campaignType,
|
|
172
|
+
),
|
|
173
|
+
)
|
|
174
|
+
android.util.Log.d("DigiaAnalytics", "[trackEvent] forwarding to Digia.captureAnalyticsEvent: event=${event::class.simpleName}")
|
|
175
|
+
Digia.captureAnalyticsEvent(event, payload)
|
|
176
|
+
}
|
|
177
|
+
|
|
129
178
|
// ─── triggerCampaign ──────────────────────────────────────────────────────
|
|
130
179
|
|
|
131
180
|
/**
|
|
@@ -138,11 +187,20 @@ internal class DigiaModule(
|
|
|
138
187
|
@ReactMethod
|
|
139
188
|
fun triggerCampaign(id: String, content: ReadableMap, cepContext: ReadableMap) {
|
|
140
189
|
val delegate = rnPlugin.delegate ?: return
|
|
190
|
+
val contentMap = content.toHashMap().toMap()
|
|
191
|
+
val campaignKey = (contentMap["digia_campaign_key"] as? String)
|
|
192
|
+
?: (contentMap["campaign_key"] as? String)
|
|
193
|
+
?: id
|
|
194
|
+
@Suppress("UNCHECKED_CAST")
|
|
195
|
+
val variables = (contentMap["variables"] as? Map<*, *>)
|
|
196
|
+
?.entries
|
|
197
|
+
?.associate { it.key.toString() to it.value?.toString().orEmpty() }
|
|
141
198
|
delegate.onCampaignTriggered(
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
199
|
+
CEPTriggerPayload(
|
|
200
|
+
cepCampaignId = id,
|
|
201
|
+
campaignKey = campaignKey,
|
|
202
|
+
cepMetadata = cepContext.toHashMap().toMap(),
|
|
203
|
+
variables = variables,
|
|
146
204
|
)
|
|
147
205
|
)
|
|
148
206
|
}
|
|
@@ -277,10 +335,10 @@ internal class RNEventBridgePlugin(
|
|
|
277
335
|
/* forwarded by Digia.setCurrentScreen() on the native side */
|
|
278
336
|
}
|
|
279
337
|
|
|
280
|
-
override fun notifyEvent(event: DigiaExperienceEvent, payload:
|
|
338
|
+
override fun notifyEvent(event: DigiaExperienceEvent, payload: CEPTriggerPayload) {
|
|
281
339
|
val params =
|
|
282
340
|
Arguments.createMap().apply {
|
|
283
|
-
putString("campaignId", payload.
|
|
341
|
+
putString("campaignId", payload.cepCampaignId)
|
|
284
342
|
when (event) {
|
|
285
343
|
is DigiaExperienceEvent.Impressed -> putString("type", "impressed")
|
|
286
344
|
is DigiaExperienceEvent.Clicked -> {
|
package/ios/DigiaModule.swift
CHANGED
|
@@ -78,13 +78,18 @@ final class DigiaModule: RCTEventEmitter {
|
|
|
78
78
|
default: logLevelValue = .error
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
let cleanBaseUrl = baseUrl.flatMap { url -> String? in
|
|
82
|
+
var s = url.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
83
|
+
.trimmingCharacters(in: CharacterSet(charactersIn: "/"))
|
|
84
|
+
if s.hasSuffix("/api/v1") { s = String(s.dropLast(7)) }
|
|
85
|
+
return s.isEmpty ? nil : s
|
|
86
|
+
}
|
|
87
|
+
|
|
81
88
|
let config = DigiaConfig(
|
|
82
89
|
apiKey: projectId,
|
|
83
90
|
logLevel: logLevelValue,
|
|
84
91
|
environment: envValue,
|
|
85
|
-
developerConfig:
|
|
86
|
-
$0.isEmpty ? nil : DigiaDeveloperConfig(baseURL: $0)
|
|
87
|
-
},
|
|
92
|
+
developerConfig: cleanBaseUrl.map { DigiaDeveloperConfig(baseURL: $0) },
|
|
88
93
|
fontFamily: fontFamily.flatMap { $0.isEmpty ? nil : $0 }
|
|
89
94
|
)
|
|
90
95
|
|
|
@@ -109,10 +114,27 @@ final class DigiaModule: RCTEventEmitter {
|
|
|
109
114
|
@objc
|
|
110
115
|
func registerBridge() {
|
|
111
116
|
Task { @MainActor in
|
|
117
|
+
// Dismiss any stale overlay left over from the previous JS session.
|
|
118
|
+
Digia.dismissActiveNudge()
|
|
119
|
+
|
|
120
|
+
// After a JS reload, re-bring the overlay host to the front.
|
|
121
|
+
// Expo/RN may have added views during the reload cycle that sit on
|
|
122
|
+
// top of the host, causing the SwiftUI layer to be unreachable by
|
|
123
|
+
// touch even when hasActiveOverlay = true.
|
|
124
|
+
if let rootVC = UIApplication.shared.connectedScenes
|
|
125
|
+
.compactMap({ ($0 as? UIWindowScene)?.keyWindow?.rootViewController })
|
|
126
|
+
.first,
|
|
127
|
+
let hostView = rootVC.view.viewWithTag(Self.overlayMountTag) {
|
|
128
|
+
rootVC.view.bringSubviewToFront(hostView)
|
|
129
|
+
}
|
|
130
|
+
|
|
112
131
|
Digia.register(self.rnPlugin)
|
|
132
|
+
print("[DigiaRN] registerBridge: rnPlugin registered, delegate=\(self.rnPlugin.delegate != nil ? "set" : "nil")")
|
|
113
133
|
}
|
|
114
134
|
}
|
|
115
135
|
|
|
136
|
+
private static let overlayMountTag = 0xD19140
|
|
137
|
+
|
|
116
138
|
// ────────────────────────────────────────────────────────────────────────
|
|
117
139
|
// MARK: - setCurrentScreen
|
|
118
140
|
|
|
@@ -140,10 +162,17 @@ final class DigiaModule: RCTEventEmitter {
|
|
|
140
162
|
let content = buildInAppPayloadContent(from: contentMap)
|
|
141
163
|
let cepContext = (cepContextMap as? [String: String]) ?? [:]
|
|
142
164
|
let payload = InAppPayload(id: id, content: content, cepContext: cepContext)
|
|
165
|
+
print("[DigiaRN] triggerCampaign id=\(id) campaignKey=\(content.campaignKey ?? "nil")")
|
|
143
166
|
|
|
144
167
|
Task { @MainActor in
|
|
145
|
-
guard let delegate = self.rnPlugin.delegate else {
|
|
168
|
+
guard let delegate = self.rnPlugin.delegate else {
|
|
169
|
+
print("[DigiaRN] triggerCampaign: delegate is nil — registerBridge() may not have run yet")
|
|
170
|
+
return
|
|
171
|
+
}
|
|
146
172
|
delegate.onCampaignTriggered(payload)
|
|
173
|
+
Task { @MainActor in
|
|
174
|
+
print("[DigiaRN] triggerCampaign post-call: hasActiveOverlay=\(Digia.hasActiveOverlay)")
|
|
175
|
+
}
|
|
147
176
|
}
|
|
148
177
|
}
|
|
149
178
|
|
|
@@ -213,12 +242,11 @@ final class DigiaModule: RCTEventEmitter {
|
|
|
213
242
|
else { return }
|
|
214
243
|
|
|
215
244
|
// Guard against double-mounting (e.g. fast-refresh).
|
|
216
|
-
|
|
217
|
-
if rootVC.view.viewWithTag(mountTag) != nil { return }
|
|
245
|
+
if rootVC.view.viewWithTag(Self.overlayMountTag) != nil { return }
|
|
218
246
|
|
|
219
247
|
let hc = UIHostingController(rootView: DigiaHostWrapperView())
|
|
220
248
|
let hostView = DigiaRootOverlayView(hostingController: hc)
|
|
221
|
-
hostView.tag =
|
|
249
|
+
hostView.tag = Self.overlayMountTag
|
|
222
250
|
hostView.translatesAutoresizingMaskIntoConstraints = false
|
|
223
251
|
hostView.backgroundColor = .clear
|
|
224
252
|
|
|
@@ -254,6 +282,7 @@ final class DigiaModule: RCTEventEmitter {
|
|
|
254
282
|
let screenId = map["screenId"] as? String
|
|
255
283
|
let campaignKey =
|
|
256
284
|
(map["campaignKey"] as? String) ?? (map["campaign_key"] as? String)
|
|
285
|
+
?? (map["digia_campaign_key"] as? String)
|
|
257
286
|
?? (map["digiaKey"] as? String)
|
|
258
287
|
var type = (map["type"] as? String)?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
259
288
|
if type.isEmpty {
|
|
@@ -266,6 +295,13 @@ final class DigiaModule: RCTEventEmitter {
|
|
|
266
295
|
return raw.compactMapValues { JSONValue(rawValue: $0) }
|
|
267
296
|
}()
|
|
268
297
|
|
|
298
|
+
// CEP trigger variables for `{{ }}` interpolation. CleverTap's nudge
|
|
299
|
+
// mapper puts them at `content.variables` (top-level); the command/inline
|
|
300
|
+
// mappers may nest them under `args.variables`. Mirror the JS bridge's
|
|
301
|
+
// `_extractVariables` (content.variables first, then args.variables).
|
|
302
|
+
let variables = Self.variableMap(map["variables"])
|
|
303
|
+
?? Self.variableMap((map["args"] as? [String: Any])?["variables"])
|
|
304
|
+
|
|
269
305
|
return InAppPayloadContent(
|
|
270
306
|
type: type,
|
|
271
307
|
placementKey: pk,
|
|
@@ -275,9 +311,35 @@ final class DigiaModule: RCTEventEmitter {
|
|
|
275
311
|
command: command,
|
|
276
312
|
args: args,
|
|
277
313
|
screenId: screenId,
|
|
278
|
-
campaignKey: campaignKey
|
|
314
|
+
campaignKey: campaignKey,
|
|
315
|
+
variables: variables
|
|
279
316
|
)
|
|
280
317
|
}
|
|
318
|
+
|
|
319
|
+
/// Coerces a raw `variables` value into a `[String: String]` map, stringifying
|
|
320
|
+
/// scalar values (string / number / bool) and dropping anything else. Returns
|
|
321
|
+
/// nil for a missing or empty map. Mirrors the JS `parseVariableMap`.
|
|
322
|
+
private static func variableMap(_ raw: Any?) -> [String: String]? {
|
|
323
|
+
guard let dict = raw as? [String: Any] else { return nil }
|
|
324
|
+
var result: [String: String] = [:]
|
|
325
|
+
for (key, value) in dict {
|
|
326
|
+
switch value {
|
|
327
|
+
case let string as String:
|
|
328
|
+
result[key] = string
|
|
329
|
+
case let number as NSNumber:
|
|
330
|
+
// Distinguish a boxed bool from a numeric NSNumber so `true`
|
|
331
|
+
// stays "true" rather than "1".
|
|
332
|
+
if CFGetTypeID(number) == CFBooleanGetTypeID() {
|
|
333
|
+
result[key] = number.boolValue ? "true" : "false"
|
|
334
|
+
} else {
|
|
335
|
+
result[key] = number.stringValue
|
|
336
|
+
}
|
|
337
|
+
default:
|
|
338
|
+
continue
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
return result.isEmpty ? nil : result
|
|
342
|
+
}
|
|
281
343
|
}
|
|
282
344
|
|
|
283
345
|
// MARK: - DigiaRootOverlayView
|
|
@@ -54,6 +54,8 @@ internal final class RNEventBridgePlugin: NSObject, DigiaCEPPlugin {
|
|
|
54
54
|
case .dismissed:
|
|
55
55
|
body["type"] = "dismissed"
|
|
56
56
|
}
|
|
57
|
+
let hasEmitter = eventEmitter != nil
|
|
58
|
+
print("[DigiaRN] RNEventBridgePlugin.notifyEvent type=\(body["type"] ?? "?") campaignId=\(payload.id) hasEmitter=\(hasEmitter)")
|
|
57
59
|
eventEmitter?.sendEvent(withName: "digiaEngageEvent", body: body)
|
|
58
60
|
}
|
|
59
61
|
|