@ordersune/crm-web-sdk 1.0.13 → 1.0.15
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 +249 -249
- package/dist/index.js +1 -5
- package/package.json +41 -24
- package/dist/types/index.js +0 -3
- package/dist/utils/index.js +0 -9
- package/dist/web-sdk.js +0 -583
package/dist/web-sdk.js
DELETED
|
@@ -1,583 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.WebSDK = void 0;
|
|
4
|
-
const utils_1 = require("./utils");
|
|
5
|
-
const uuid_1 = require("uuid");
|
|
6
|
-
const STORAGE_PREFIX = "os.";
|
|
7
|
-
const DEFAULT_BATCH_SIZE = 10;
|
|
8
|
-
const DEFAULT_BATCH_INTERVAL = 10000;
|
|
9
|
-
const SDK_VERSION = "1.0.7";
|
|
10
|
-
class WebSDK {
|
|
11
|
-
constructor(config) {
|
|
12
|
-
var _a, _b, _c;
|
|
13
|
-
this.maxBatchSize = DEFAULT_BATCH_SIZE;
|
|
14
|
-
this.batchInterval = DEFAULT_BATCH_INTERVAL;
|
|
15
|
-
this.sdkVersion = SDK_VERSION;
|
|
16
|
-
this.eventQueue = [];
|
|
17
|
-
this.purchaseBatch = [];
|
|
18
|
-
this.attributeQueue = {};
|
|
19
|
-
this.isProcessingQueue = false;
|
|
20
|
-
if (!config.apiKey || !config.endpoint) {
|
|
21
|
-
throw new Error("API key and endpoint are required");
|
|
22
|
-
}
|
|
23
|
-
this.apiKey = config.apiKey;
|
|
24
|
-
this.endpoint = config.endpoint;
|
|
25
|
-
this.debug = (_a = config.debug) !== null && _a !== void 0 ? _a : false;
|
|
26
|
-
this.maxBatchSize = (_b = config.batchSize) !== null && _b !== void 0 ? _b : DEFAULT_BATCH_SIZE;
|
|
27
|
-
this.batchInterval = (_c = config.batchInterval) !== null && _c !== void 0 ? _c : DEFAULT_BATCH_INTERVAL;
|
|
28
|
-
this.deviceId = this.getStoredDeviceId() || (0, uuid_1.v4)();
|
|
29
|
-
this.guestUserId = this.getGuestUserId();
|
|
30
|
-
// Initialize async
|
|
31
|
-
this.initialize().catch((error) => {
|
|
32
|
-
(0, utils_1.log)(this.debug, "Async initialization failed", error);
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
async initialize() {
|
|
36
|
-
try {
|
|
37
|
-
(0, utils_1.log)(this.debug, "SDK Initialized");
|
|
38
|
-
this.storeDeviceId();
|
|
39
|
-
await this.initializeDeviceDetails();
|
|
40
|
-
await this.loadCustomAttributes();
|
|
41
|
-
const storedUser = this.getStoredUserProfile();
|
|
42
|
-
if (storedUser) {
|
|
43
|
-
this.currentUser = storedUser;
|
|
44
|
-
(0, utils_1.log)(this.debug, "Loaded user profile", this.currentUser);
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
this.identify("");
|
|
48
|
-
}
|
|
49
|
-
try {
|
|
50
|
-
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
51
|
-
this.trackCustomAttribute("timezone", timezone);
|
|
52
|
-
}
|
|
53
|
-
catch (error) {
|
|
54
|
-
(0, utils_1.log)(this.debug, "Failed to detect timezone", error);
|
|
55
|
-
}
|
|
56
|
-
this.startBatchProcessing();
|
|
57
|
-
this.trackEvent("app_started", {});
|
|
58
|
-
}
|
|
59
|
-
catch (error) {
|
|
60
|
-
(0, utils_1.log)(this.debug, "Initialization failed", error);
|
|
61
|
-
throw error;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
identify(userId) {
|
|
65
|
-
if (typeof userId !== "string") {
|
|
66
|
-
throw new Error("User ID must be a string");
|
|
67
|
-
}
|
|
68
|
-
const storedUser = this.getStoredUserProfile();
|
|
69
|
-
if ((storedUser === null || storedUser === void 0 ? void 0 : storedUser.id) === userId)
|
|
70
|
-
return;
|
|
71
|
-
(0, utils_1.log)(this.debug, "Identifying user", userId);
|
|
72
|
-
// If userId is empty or matches guest pattern, use guest user
|
|
73
|
-
if (!userId) {
|
|
74
|
-
this.currentUser = {
|
|
75
|
-
id: this.guestUserId,
|
|
76
|
-
guestUserId: this.guestUserId
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
else {
|
|
80
|
-
// Real user identification - include both userId and guestUserId
|
|
81
|
-
this.currentUser = {
|
|
82
|
-
id: userId,
|
|
83
|
-
guestUserId: this.guestUserId
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
this.storeUserProfile();
|
|
87
|
-
}
|
|
88
|
-
clearUserData() {
|
|
89
|
-
// Generate new device ID
|
|
90
|
-
this.deviceId = (0, uuid_1.v4)();
|
|
91
|
-
this.guestUserId = this.getGuestUserId();
|
|
92
|
-
this.currentUser = {
|
|
93
|
-
id: this.guestUserId,
|
|
94
|
-
guestUserId: this.guestUserId
|
|
95
|
-
};
|
|
96
|
-
this.attributeQueue = {};
|
|
97
|
-
this.eventQueue = [];
|
|
98
|
-
this.purchaseBatch = [];
|
|
99
|
-
this.storeDeviceId();
|
|
100
|
-
sessionStorage.setItem(`${STORAGE_PREFIX}${this.apiKey}.current_user`, JSON.stringify(this.currentUser));
|
|
101
|
-
sessionStorage.removeItem(`${STORAGE_PREFIX}${this.apiKey}.custom_attributes`);
|
|
102
|
-
if (this.debug) {
|
|
103
|
-
(0, utils_1.log)(this.debug, "User data cleared, new device ID generated");
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
trackEvent(eventName, properties = {}, options = {}) {
|
|
107
|
-
if (!eventName || typeof eventName !== "string") {
|
|
108
|
-
throw new Error("Event name is required and must be a string");
|
|
109
|
-
}
|
|
110
|
-
const payload = {
|
|
111
|
-
deviceId: this.deviceId,
|
|
112
|
-
eventName,
|
|
113
|
-
timestamp: options.timestamp || Date.now(),
|
|
114
|
-
requestId: options.requestId || (0, uuid_1.v4)(),
|
|
115
|
-
properties: properties,
|
|
116
|
-
};
|
|
117
|
-
this.queueEvent(payload);
|
|
118
|
-
}
|
|
119
|
-
setToken(token) {
|
|
120
|
-
if (this.deviceDetails) {
|
|
121
|
-
this.deviceDetails = {
|
|
122
|
-
...this.deviceDetails,
|
|
123
|
-
pushToken: token,
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
trackCustomAttribute(attributeName, attributeValue) {
|
|
128
|
-
if (!attributeName || typeof attributeName !== "string") {
|
|
129
|
-
throw new Error("Attribute name is required and must be a string");
|
|
130
|
-
}
|
|
131
|
-
this.attributeQueue = {
|
|
132
|
-
...this.attributeQueue,
|
|
133
|
-
[attributeName]: attributeValue,
|
|
134
|
-
};
|
|
135
|
-
(0, utils_1.log)(this.debug, "Custom attribute queued", attributeName, attributeValue);
|
|
136
|
-
this.storeCustomAttributes();
|
|
137
|
-
}
|
|
138
|
-
logProductPurchase(orderId, itemId, itemName, unitPrice, quantity, source, channel, itemCategory) {
|
|
139
|
-
const purchasePayload = this.buildPurchasePayload({
|
|
140
|
-
externalId: orderId,
|
|
141
|
-
itemId,
|
|
142
|
-
itemName,
|
|
143
|
-
unitPrice,
|
|
144
|
-
quantity,
|
|
145
|
-
source,
|
|
146
|
-
channel,
|
|
147
|
-
itemCategory,
|
|
148
|
-
});
|
|
149
|
-
this.purchaseBatch.push(purchasePayload);
|
|
150
|
-
if (this.debug) {
|
|
151
|
-
(0, utils_1.log)(this.debug, "Purchase event queued", purchasePayload);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
getUserProfile() {
|
|
155
|
-
return this.currentUser;
|
|
156
|
-
}
|
|
157
|
-
async forceSend() {
|
|
158
|
-
if (this.eventQueue.length > 0 ||
|
|
159
|
-
this.purchaseBatch.length > 0 ||
|
|
160
|
-
this.attributeQueue.length > 0) {
|
|
161
|
-
await this.processBatch();
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
dispose() {
|
|
165
|
-
if (this.batchProcessingInterval) {
|
|
166
|
-
clearInterval(this.batchProcessingInterval);
|
|
167
|
-
}
|
|
168
|
-
if (this.eventQueue.length > 0 ||
|
|
169
|
-
this.purchaseBatch.length > 0 ||
|
|
170
|
-
this.attributeQueue.length > 0) {
|
|
171
|
-
this.processBatch().catch((error) => {
|
|
172
|
-
(0, utils_1.log)(this.debug, "Error during disposal", error);
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
getStoredDeviceId() {
|
|
177
|
-
return sessionStorage.getItem(`${STORAGE_PREFIX}${this.apiKey}.device_id`);
|
|
178
|
-
}
|
|
179
|
-
getStoredUserProfile() {
|
|
180
|
-
const storedUser = sessionStorage.getItem(`${STORAGE_PREFIX}${this.apiKey}.current_user`);
|
|
181
|
-
return storedUser ? JSON.parse(storedUser) : null;
|
|
182
|
-
}
|
|
183
|
-
storeDeviceId() {
|
|
184
|
-
sessionStorage.setItem(`${STORAGE_PREFIX}${this.apiKey}.device_id`, this.deviceId);
|
|
185
|
-
}
|
|
186
|
-
storeUserProfile() {
|
|
187
|
-
if (this.currentUser) {
|
|
188
|
-
sessionStorage.setItem(`${STORAGE_PREFIX}${this.apiKey}.current_user`, JSON.stringify(this.currentUser));
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
storeCustomAttributes() {
|
|
192
|
-
const existingAttributes = sessionStorage.getItem(`${STORAGE_PREFIX}${this.apiKey}.custom_attributes`);
|
|
193
|
-
const existingParsed = existingAttributes
|
|
194
|
-
? JSON.parse(existingAttributes)
|
|
195
|
-
: {};
|
|
196
|
-
const mergedAttributes = {
|
|
197
|
-
...existingParsed,
|
|
198
|
-
...this.attributeQueue,
|
|
199
|
-
};
|
|
200
|
-
sessionStorage.setItem(`${STORAGE_PREFIX}${this.apiKey}.custom_attributes`, JSON.stringify(mergedAttributes));
|
|
201
|
-
}
|
|
202
|
-
async loadCustomAttributes() {
|
|
203
|
-
const stored = sessionStorage.getItem(`${STORAGE_PREFIX}${this.apiKey}.custom_attributes`);
|
|
204
|
-
if (stored) {
|
|
205
|
-
this.attributeQueue = {
|
|
206
|
-
...this.attributeQueue,
|
|
207
|
-
...JSON.parse(stored),
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
getGuestUserId() {
|
|
212
|
-
return `guest_user_${this.deviceId}`;
|
|
213
|
-
}
|
|
214
|
-
buildPurchasePayload({ externalId, itemId, itemName, unitPrice, quantity, source, channel, itemCategory, }) {
|
|
215
|
-
const timestamp = Date.now();
|
|
216
|
-
return {
|
|
217
|
-
external_id: externalId,
|
|
218
|
-
item_id: itemId,
|
|
219
|
-
item_name: itemName,
|
|
220
|
-
item_category: itemCategory,
|
|
221
|
-
quantity: quantity,
|
|
222
|
-
unit_price: unitPrice,
|
|
223
|
-
total_price: unitPrice * quantity,
|
|
224
|
-
source: source,
|
|
225
|
-
channel: channel,
|
|
226
|
-
purchased_at: timestamp,
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
async initializeDeviceDetails() {
|
|
230
|
-
this.deviceDetails = {
|
|
231
|
-
deviceId: this.deviceId,
|
|
232
|
-
platform: 'web',
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
startBatchProcessing() {
|
|
236
|
-
this.batchProcessingInterval = setInterval(() => {
|
|
237
|
-
if (this.eventQueue.length > 0 ||
|
|
238
|
-
this.purchaseBatch.length > 0 ||
|
|
239
|
-
this.attributeQueue.length > 0) {
|
|
240
|
-
this.processBatch().catch((error) => {
|
|
241
|
-
(0, utils_1.log)(this.debug, "Batch processing failed", error);
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
}, this.batchInterval);
|
|
245
|
-
}
|
|
246
|
-
queueEvent(payload) {
|
|
247
|
-
this.eventQueue.push(payload);
|
|
248
|
-
(0, utils_1.log)(this.debug, "Event queued", payload);
|
|
249
|
-
if (this.eventQueue.length >= this.maxBatchSize) {
|
|
250
|
-
this.processBatch().catch((error) => {
|
|
251
|
-
(0, utils_1.log)(this.debug, "Batch processing failed", error);
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
async processBatch() {
|
|
256
|
-
if (this.isProcessingQueue)
|
|
257
|
-
return;
|
|
258
|
-
this.isProcessingQueue = true;
|
|
259
|
-
const eventsToSend = [...this.eventQueue];
|
|
260
|
-
const purchasesToSend = [...this.purchaseBatch];
|
|
261
|
-
const attributesToSend = { ...this.attributeQueue };
|
|
262
|
-
this.eventQueue = [];
|
|
263
|
-
this.purchaseBatch = [];
|
|
264
|
-
this.attributeQueue = {};
|
|
265
|
-
try {
|
|
266
|
-
await this.sendBatchToServer(eventsToSend, purchasesToSend, attributesToSend);
|
|
267
|
-
}
|
|
268
|
-
catch (error) {
|
|
269
|
-
this.eventQueue.unshift(...eventsToSend);
|
|
270
|
-
this.purchaseBatch.unshift(...purchasesToSend);
|
|
271
|
-
this.attributeQueue = { ...this.attributeQueue, ...attributesToSend };
|
|
272
|
-
(0, utils_1.log)(this.debug, "Batch processing failed", error);
|
|
273
|
-
throw error;
|
|
274
|
-
}
|
|
275
|
-
finally {
|
|
276
|
-
this.isProcessingQueue = false;
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
async sendBatchToServer(events, purchases, currentAttributes) {
|
|
280
|
-
var _a, _b;
|
|
281
|
-
if (!this.deviceDetails) {
|
|
282
|
-
await this.initializeDeviceDetails();
|
|
283
|
-
}
|
|
284
|
-
const payload = {
|
|
285
|
-
sdkVersion: this.sdkVersion,
|
|
286
|
-
deviceInfo: this.deviceDetails,
|
|
287
|
-
userId: (_a = this.currentUser) === null || _a === void 0 ? void 0 : _a.id,
|
|
288
|
-
guestUserId: (_b = this.currentUser) === null || _b === void 0 ? void 0 : _b.guestUserId,
|
|
289
|
-
time: Date.now(),
|
|
290
|
-
events: events,
|
|
291
|
-
purchases: purchases,
|
|
292
|
-
userAttributes: currentAttributes,
|
|
293
|
-
};
|
|
294
|
-
(0, utils_1.log)(this.debug, "Sending batch to server", payload);
|
|
295
|
-
try {
|
|
296
|
-
const response = await fetch(`${this.endpoint}/analytics/data`, {
|
|
297
|
-
method: "POST",
|
|
298
|
-
headers: {
|
|
299
|
-
"Content-Type": "application/json",
|
|
300
|
-
"x-api-key": this.apiKey,
|
|
301
|
-
},
|
|
302
|
-
body: JSON.stringify(payload),
|
|
303
|
-
});
|
|
304
|
-
if (!response.ok) {
|
|
305
|
-
throw new Error(`HTTP error! status: ${response.status}`);
|
|
306
|
-
}
|
|
307
|
-
if (this.debug) {
|
|
308
|
-
(0, utils_1.log)(this.debug, `Batch dispatched successfully: ${payload.events.length} events, ${payload.purchases.length} purchases, ${Object.keys(payload.userAttributes).length} attributes`);
|
|
309
|
-
}
|
|
310
|
-
await response.json();
|
|
311
|
-
if (Object.keys(currentAttributes).length > 0) {
|
|
312
|
-
this.attributeQueue = {};
|
|
313
|
-
sessionStorage.removeItem(`${STORAGE_PREFIX}${this.apiKey}.custom_attributes`);
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
catch (error) {
|
|
317
|
-
(0, utils_1.log)(this.debug, "Failed to send payload to server", error);
|
|
318
|
-
throw error;
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
displayInAppMessage(inAppMessageData, campaignId, context) {
|
|
322
|
-
const transformedData = JSON.parse(inAppMessageData);
|
|
323
|
-
const title = transformedData.header;
|
|
324
|
-
const body = transformedData.message;
|
|
325
|
-
const buttonDataPrimary = transformedData.modal.button1;
|
|
326
|
-
const buttonDataSecondary = transformedData.modal.button2;
|
|
327
|
-
const buttonTextPrimary = buttonDataPrimary.type || "";
|
|
328
|
-
const buttonTextSecondary = buttonDataSecondary.type || "";
|
|
329
|
-
const imageUrl = transformedData.mediaConfig.inAppImage;
|
|
330
|
-
this.showInAppMessage({
|
|
331
|
-
context,
|
|
332
|
-
title,
|
|
333
|
-
body,
|
|
334
|
-
primaryButtonText: buttonTextPrimary,
|
|
335
|
-
secondaryButtonText: buttonTextSecondary,
|
|
336
|
-
imageUrl,
|
|
337
|
-
buttonPropertiesPrimary: buttonDataPrimary,
|
|
338
|
-
buttonPropertiesSecondary: buttonDataSecondary,
|
|
339
|
-
dismissMessageAutomatically: transformedData.modal.dismissMessageAutomatically,
|
|
340
|
-
dismissMessageInSeconds: transformedData.modal.dismissMessageInSeconds,
|
|
341
|
-
headerColor: transformedData.modal.headerColor,
|
|
342
|
-
messageColor: transformedData.modal.messageColor,
|
|
343
|
-
closeColor: transformedData.modal.closeColor,
|
|
344
|
-
campaignId: campaignId,
|
|
345
|
-
});
|
|
346
|
-
}
|
|
347
|
-
hexToColor(hexColor) {
|
|
348
|
-
hexColor = hexColor.toUpperCase().replace("#", "");
|
|
349
|
-
if (hexColor.length === 6) {
|
|
350
|
-
return `#${hexColor}`;
|
|
351
|
-
}
|
|
352
|
-
return `#${hexColor.substring(2)}`;
|
|
353
|
-
}
|
|
354
|
-
openWebUrl(url) {
|
|
355
|
-
if (url) {
|
|
356
|
-
window.open(url, '_blank');
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
showInAppMessage(options) {
|
|
360
|
-
const { title, body, primaryButtonText, secondaryButtonText, imageUrl, onClose, buttonPropertiesPrimary, buttonPropertiesSecondary, dismissMessageAutomatically, dismissMessageInSeconds, headerColor, messageColor, closeColor, campaignId, } = options;
|
|
361
|
-
// Create modal container
|
|
362
|
-
const modalOverlay = document.createElement('div');
|
|
363
|
-
modalOverlay.style.position = 'fixed';
|
|
364
|
-
modalOverlay.style.top = '0';
|
|
365
|
-
modalOverlay.style.left = '0';
|
|
366
|
-
modalOverlay.style.width = '100%';
|
|
367
|
-
modalOverlay.style.height = '100%';
|
|
368
|
-
modalOverlay.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
|
|
369
|
-
modalOverlay.style.display = 'flex';
|
|
370
|
-
modalOverlay.style.justifyContent = 'center';
|
|
371
|
-
modalOverlay.style.alignItems = 'center';
|
|
372
|
-
modalOverlay.style.zIndex = '9999';
|
|
373
|
-
// Create modal dialog
|
|
374
|
-
const modalDialog = document.createElement('div');
|
|
375
|
-
modalDialog.style.backgroundColor = 'white';
|
|
376
|
-
modalDialog.style.borderRadius = '12px';
|
|
377
|
-
modalDialog.style.padding = '16px';
|
|
378
|
-
modalDialog.style.maxWidth = '400px';
|
|
379
|
-
modalDialog.style.width = '90%';
|
|
380
|
-
modalDialog.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.1)';
|
|
381
|
-
modalDialog.style.position = 'relative';
|
|
382
|
-
// Close button
|
|
383
|
-
const closeButton = document.createElement('button');
|
|
384
|
-
closeButton.innerHTML = '×';
|
|
385
|
-
closeButton.style.position = 'absolute';
|
|
386
|
-
closeButton.style.top = '8px';
|
|
387
|
-
closeButton.style.right = '8px';
|
|
388
|
-
closeButton.style.background = 'none';
|
|
389
|
-
closeButton.style.border = 'none';
|
|
390
|
-
closeButton.style.fontSize = '20px';
|
|
391
|
-
closeButton.style.cursor = 'pointer';
|
|
392
|
-
closeButton.style.color = this.hexToColor(closeColor);
|
|
393
|
-
closeButton.onclick = () => {
|
|
394
|
-
if (onClose) {
|
|
395
|
-
onClose();
|
|
396
|
-
}
|
|
397
|
-
this.logInAppMessageClick(campaignId, false, true, true);
|
|
398
|
-
document.body.removeChild(modalOverlay);
|
|
399
|
-
};
|
|
400
|
-
// Create content
|
|
401
|
-
const contentContainer = document.createElement('div');
|
|
402
|
-
contentContainer.style.display = 'flex';
|
|
403
|
-
contentContainer.style.flexDirection = 'column';
|
|
404
|
-
contentContainer.style.alignItems = 'center';
|
|
405
|
-
contentContainer.style.textAlign = 'center';
|
|
406
|
-
// Image
|
|
407
|
-
if (imageUrl && imageUrl.trim() !== '') {
|
|
408
|
-
const image = document.createElement('img');
|
|
409
|
-
image.src = imageUrl;
|
|
410
|
-
image.style.width = '100px';
|
|
411
|
-
image.style.height = '100px';
|
|
412
|
-
image.style.marginBottom = '16px';
|
|
413
|
-
image.style.marginTop = '16px';
|
|
414
|
-
image.onerror = () => {
|
|
415
|
-
image.style.display = 'none';
|
|
416
|
-
};
|
|
417
|
-
contentContainer.appendChild(image);
|
|
418
|
-
}
|
|
419
|
-
// Title
|
|
420
|
-
const titleElement = document.createElement('h2');
|
|
421
|
-
titleElement.textContent = title;
|
|
422
|
-
titleElement.style.fontSize = '22px';
|
|
423
|
-
titleElement.style.fontWeight = '600';
|
|
424
|
-
titleElement.style.color = this.hexToColor(headerColor);
|
|
425
|
-
titleElement.style.margin = '8px 0';
|
|
426
|
-
contentContainer.appendChild(titleElement);
|
|
427
|
-
// Body
|
|
428
|
-
const bodyElement = document.createElement('p');
|
|
429
|
-
bodyElement.textContent = body;
|
|
430
|
-
bodyElement.style.fontSize = '14px';
|
|
431
|
-
bodyElement.style.color = this.hexToColor(messageColor);
|
|
432
|
-
bodyElement.style.fontWeight = '500';
|
|
433
|
-
bodyElement.style.margin = '8px 0 24px 0';
|
|
434
|
-
contentContainer.appendChild(bodyElement);
|
|
435
|
-
// Button handlers
|
|
436
|
-
const onPrimaryButtonPress = () => {
|
|
437
|
-
if (buttonPropertiesPrimary.webOnClickValue === "redirect_to_web_url" ||
|
|
438
|
-
buttonPropertiesPrimary.webOnClickValue === "deeplink_into_app") {
|
|
439
|
-
this.openWebUrl(buttonPropertiesPrimary.webOnClickAction || '');
|
|
440
|
-
}
|
|
441
|
-
};
|
|
442
|
-
const onSecondaryButtonPress = () => {
|
|
443
|
-
if (buttonPropertiesSecondary.webOnClickValue === "redirect_to_web_url" ||
|
|
444
|
-
buttonPropertiesSecondary.webOnClickValue === "deeplink_into_app") {
|
|
445
|
-
this.openWebUrl(buttonPropertiesSecondary.webOnClickAction || '');
|
|
446
|
-
}
|
|
447
|
-
};
|
|
448
|
-
// Create buttons
|
|
449
|
-
const buttonsContainer = document.createElement('div');
|
|
450
|
-
buttonsContainer.style.display = 'flex';
|
|
451
|
-
buttonsContainer.style.justifyContent = 'center';
|
|
452
|
-
buttonsContainer.style.width = '100%';
|
|
453
|
-
buttonsContainer.style.gap = '16px';
|
|
454
|
-
if (secondaryButtonText && secondaryButtonText.trim() !== '') {
|
|
455
|
-
// Primary button
|
|
456
|
-
const primaryButton = document.createElement('button');
|
|
457
|
-
primaryButton.textContent = primaryButtonText;
|
|
458
|
-
primaryButton.style.flex = '1';
|
|
459
|
-
primaryButton.style.maxWidth = '140px';
|
|
460
|
-
primaryButton.style.padding = '12px';
|
|
461
|
-
primaryButton.style.backgroundColor = this.hexToColor(buttonPropertiesPrimary.backgroundColor);
|
|
462
|
-
primaryButton.style.color = this.hexToColor(buttonPropertiesPrimary.textColor);
|
|
463
|
-
primaryButton.style.border = `2px solid ${this.hexToColor(buttonPropertiesPrimary.borderColor)}`;
|
|
464
|
-
primaryButton.style.borderRadius = '8px';
|
|
465
|
-
primaryButton.style.fontSize = '16px';
|
|
466
|
-
primaryButton.style.fontWeight = '600';
|
|
467
|
-
primaryButton.style.cursor = 'pointer';
|
|
468
|
-
primaryButton.onclick = () => {
|
|
469
|
-
document.body.removeChild(modalOverlay);
|
|
470
|
-
onPrimaryButtonPress();
|
|
471
|
-
};
|
|
472
|
-
buttonsContainer.appendChild(primaryButton);
|
|
473
|
-
// Secondary button
|
|
474
|
-
const secondaryButton = document.createElement('button');
|
|
475
|
-
secondaryButton.textContent = secondaryButtonText;
|
|
476
|
-
secondaryButton.style.flex = '1';
|
|
477
|
-
secondaryButton.style.maxWidth = '140px';
|
|
478
|
-
secondaryButton.style.padding = '12px';
|
|
479
|
-
secondaryButton.style.backgroundColor = this.hexToColor(buttonPropertiesSecondary.backgroundColor);
|
|
480
|
-
secondaryButton.style.color = this.hexToColor(buttonPropertiesSecondary.textColor);
|
|
481
|
-
secondaryButton.style.border = `2px solid ${this.hexToColor(buttonPropertiesSecondary.borderColor)}`;
|
|
482
|
-
secondaryButton.style.borderRadius = '8px';
|
|
483
|
-
secondaryButton.style.fontSize = '16px';
|
|
484
|
-
secondaryButton.style.fontWeight = '600';
|
|
485
|
-
secondaryButton.style.cursor = 'pointer';
|
|
486
|
-
secondaryButton.onclick = () => {
|
|
487
|
-
document.body.removeChild(modalOverlay);
|
|
488
|
-
this.logInAppMessageClick(campaignId, true, true, false);
|
|
489
|
-
onSecondaryButtonPress();
|
|
490
|
-
};
|
|
491
|
-
buttonsContainer.appendChild(secondaryButton);
|
|
492
|
-
}
|
|
493
|
-
else {
|
|
494
|
-
// Single button
|
|
495
|
-
if (primaryButtonText && primaryButtonText.trim() !== '') {
|
|
496
|
-
const primaryButton = document.createElement('button');
|
|
497
|
-
primaryButton.textContent = primaryButtonText;
|
|
498
|
-
primaryButton.style.width = '100%';
|
|
499
|
-
primaryButton.style.padding = '12px';
|
|
500
|
-
primaryButton.style.backgroundColor = this.hexToColor(buttonPropertiesPrimary.backgroundColor);
|
|
501
|
-
primaryButton.style.color = this.hexToColor(buttonPropertiesPrimary.textColor);
|
|
502
|
-
primaryButton.style.border = `2px solid ${this.hexToColor(buttonPropertiesPrimary.borderColor)}`;
|
|
503
|
-
primaryButton.style.borderRadius = '8px';
|
|
504
|
-
primaryButton.style.fontSize = '16px';
|
|
505
|
-
primaryButton.style.fontWeight = '600';
|
|
506
|
-
primaryButton.style.cursor = 'pointer';
|
|
507
|
-
primaryButton.onclick = () => {
|
|
508
|
-
document.body.removeChild(modalOverlay);
|
|
509
|
-
this.logInAppMessageClick(campaignId, true, true, false);
|
|
510
|
-
onPrimaryButtonPress();
|
|
511
|
-
};
|
|
512
|
-
buttonsContainer.appendChild(primaryButton);
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
// Add all elements to the modal
|
|
516
|
-
modalDialog.appendChild(closeButton);
|
|
517
|
-
modalDialog.appendChild(contentContainer);
|
|
518
|
-
contentContainer.appendChild(buttonsContainer);
|
|
519
|
-
modalOverlay.appendChild(modalDialog);
|
|
520
|
-
// Add to document
|
|
521
|
-
document.body.appendChild(modalOverlay);
|
|
522
|
-
// Auto dismiss if enabled
|
|
523
|
-
if (dismissMessageAutomatically) {
|
|
524
|
-
setTimeout(() => {
|
|
525
|
-
if (document.body.contains(modalOverlay)) {
|
|
526
|
-
document.body.removeChild(modalOverlay);
|
|
527
|
-
}
|
|
528
|
-
}, parseInt(dismissMessageInSeconds) * 1000);
|
|
529
|
-
}
|
|
530
|
-
// Add click event to close when clicking outside
|
|
531
|
-
modalOverlay.addEventListener('click', (event) => {
|
|
532
|
-
if (event.target === modalOverlay) {
|
|
533
|
-
document.body.removeChild(modalOverlay);
|
|
534
|
-
}
|
|
535
|
-
});
|
|
536
|
-
}
|
|
537
|
-
async logInAppMessageClick(campaignId, clicked, opened, dismissed) {
|
|
538
|
-
const campaignClickPayload = await this.buildCampaignPayload(campaignId, opened, clicked, dismissed);
|
|
539
|
-
await this.processCampaignClick(campaignClickPayload);
|
|
540
|
-
}
|
|
541
|
-
async logClick(campaignId) {
|
|
542
|
-
const pushCampaignClickPayload = await this.buildCampaignPayload(campaignId, true, true);
|
|
543
|
-
await this.processCampaignClick(pushCampaignClickPayload);
|
|
544
|
-
}
|
|
545
|
-
async processCampaignClick(payload) {
|
|
546
|
-
try {
|
|
547
|
-
const response = await fetch(`${this.endpoint}/analytics/clicks`, {
|
|
548
|
-
method: "POST",
|
|
549
|
-
headers: {
|
|
550
|
-
"Content-Type": "application/json",
|
|
551
|
-
"x-api-key": this.apiKey,
|
|
552
|
-
},
|
|
553
|
-
body: JSON.stringify(payload),
|
|
554
|
-
});
|
|
555
|
-
if (!response.ok) {
|
|
556
|
-
throw new Error(`HTTP error! status: ${response.status}`);
|
|
557
|
-
}
|
|
558
|
-
if (this.debug) {
|
|
559
|
-
(0, utils_1.log)(this.debug, `process campaign click dispatched successfully: ${payload.campaignId}`);
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
catch (error) {
|
|
563
|
-
(0, utils_1.log)(this.debug, "Error processing campaign click:", error);
|
|
564
|
-
throw error;
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
async buildCampaignPayload(campaignId, opened, clicked, dismissed) {
|
|
568
|
-
const timestamp = Date.now();
|
|
569
|
-
const deviceId = this.deviceId;
|
|
570
|
-
const payload = {
|
|
571
|
-
campaignId,
|
|
572
|
-
opened,
|
|
573
|
-
clicked,
|
|
574
|
-
deviceId,
|
|
575
|
-
timestamp,
|
|
576
|
-
};
|
|
577
|
-
if (dismissed !== undefined) {
|
|
578
|
-
payload.dismissed = dismissed;
|
|
579
|
-
}
|
|
580
|
-
return payload;
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
exports.WebSDK = WebSDK;
|