@lime-bundles/widget 0.1.0 → 0.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/dist/index.cjs +125 -175
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -32
- package/dist/index.d.ts +7 -32
- package/dist/index.js +138 -180
- package/dist/index.js.map +1 -1
- package/dist/lime-bundle.global.js +23 -39
- package/dist/lime-bundle.global.js.map +1 -1
- package/package.json +3 -8
- package/dist/lime-thankyou.cjs +0 -2
- package/dist/lime-thankyou.cjs.map +0 -1
- package/dist/lime-thankyou.global.js +0 -2
- package/dist/lime-thankyou.global.js.map +0 -1
- package/dist/lime-thankyou.js +0 -2
- package/dist/lime-thankyou.js.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -7,16 +7,20 @@ declare class LimeBundleElement extends HTMLElement {
|
|
|
7
7
|
constructor();
|
|
8
8
|
connectedCallback(): void;
|
|
9
9
|
disconnectedCallback(): void;
|
|
10
|
-
/** Clean up stale bundle state and active impression observer. */
|
|
11
10
|
private teardownImpression;
|
|
12
11
|
attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
|
|
13
12
|
private get shopDomain();
|
|
14
13
|
private get storefrontToken();
|
|
15
14
|
private get bundleGid();
|
|
16
|
-
private get cartId();
|
|
17
15
|
private get appUrl();
|
|
18
16
|
private get analyticsEnabled();
|
|
19
17
|
private fetchBundle;
|
|
18
|
+
/**
|
|
19
|
+
* Dispatch add-to-cart for merchant handling. Returns true — the widget
|
|
20
|
+
* reports success optimistically. If the merchant's cart mutation fails,
|
|
21
|
+
* they're responsible for surfacing that error in their own UI.
|
|
22
|
+
*/
|
|
23
|
+
private dispatchAddToCart;
|
|
20
24
|
private renderBundle;
|
|
21
25
|
private setupImpression;
|
|
22
26
|
private renderLoading;
|
|
@@ -24,33 +28,4 @@ declare class LimeBundleElement extends HTMLElement {
|
|
|
24
28
|
private render;
|
|
25
29
|
}
|
|
26
30
|
|
|
27
|
-
|
|
28
|
-
* Thank-you page snippet — fires purchase events for headless storefronts.
|
|
29
|
-
*
|
|
30
|
-
* Usage:
|
|
31
|
-
* <script src="https://unpkg.com/@lime-bundles/widget/dist/lime-thankyou.js"></script>
|
|
32
|
-
* <script>
|
|
33
|
-
* LimeBundles.trackPurchase({
|
|
34
|
-
* shopDomain: 'my-store.myshopify.com',
|
|
35
|
-
* orderId: 'gid://shopify/Order/12345',
|
|
36
|
-
* lineItems: [
|
|
37
|
-
* { bundleGid: '...', bundleType: 'fixed', price: 29.99, quantity: 1 }
|
|
38
|
-
* ]
|
|
39
|
-
* });
|
|
40
|
-
* </script>
|
|
41
|
-
*/
|
|
42
|
-
interface PurchaseLineItem {
|
|
43
|
-
bundleGid: string;
|
|
44
|
-
bundleType: string;
|
|
45
|
-
price: number;
|
|
46
|
-
quantity: number;
|
|
47
|
-
}
|
|
48
|
-
interface TrackPurchaseInput {
|
|
49
|
-
shopDomain: string;
|
|
50
|
-
orderId: string;
|
|
51
|
-
lineItems: PurchaseLineItem[];
|
|
52
|
-
appUrl?: string;
|
|
53
|
-
}
|
|
54
|
-
declare function trackPurchase(input: TrackPurchaseInput): void;
|
|
55
|
-
|
|
56
|
-
export { LimeBundleElement, trackPurchase };
|
|
31
|
+
export { LimeBundleElement };
|
package/dist/index.d.ts
CHANGED
|
@@ -7,16 +7,20 @@ declare class LimeBundleElement extends HTMLElement {
|
|
|
7
7
|
constructor();
|
|
8
8
|
connectedCallback(): void;
|
|
9
9
|
disconnectedCallback(): void;
|
|
10
|
-
/** Clean up stale bundle state and active impression observer. */
|
|
11
10
|
private teardownImpression;
|
|
12
11
|
attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
|
|
13
12
|
private get shopDomain();
|
|
14
13
|
private get storefrontToken();
|
|
15
14
|
private get bundleGid();
|
|
16
|
-
private get cartId();
|
|
17
15
|
private get appUrl();
|
|
18
16
|
private get analyticsEnabled();
|
|
19
17
|
private fetchBundle;
|
|
18
|
+
/**
|
|
19
|
+
* Dispatch add-to-cart for merchant handling. Returns true — the widget
|
|
20
|
+
* reports success optimistically. If the merchant's cart mutation fails,
|
|
21
|
+
* they're responsible for surfacing that error in their own UI.
|
|
22
|
+
*/
|
|
23
|
+
private dispatchAddToCart;
|
|
20
24
|
private renderBundle;
|
|
21
25
|
private setupImpression;
|
|
22
26
|
private renderLoading;
|
|
@@ -24,33 +28,4 @@ declare class LimeBundleElement extends HTMLElement {
|
|
|
24
28
|
private render;
|
|
25
29
|
}
|
|
26
30
|
|
|
27
|
-
|
|
28
|
-
* Thank-you page snippet — fires purchase events for headless storefronts.
|
|
29
|
-
*
|
|
30
|
-
* Usage:
|
|
31
|
-
* <script src="https://unpkg.com/@lime-bundles/widget/dist/lime-thankyou.js"></script>
|
|
32
|
-
* <script>
|
|
33
|
-
* LimeBundles.trackPurchase({
|
|
34
|
-
* shopDomain: 'my-store.myshopify.com',
|
|
35
|
-
* orderId: 'gid://shopify/Order/12345',
|
|
36
|
-
* lineItems: [
|
|
37
|
-
* { bundleGid: '...', bundleType: 'fixed', price: 29.99, quantity: 1 }
|
|
38
|
-
* ]
|
|
39
|
-
* });
|
|
40
|
-
* </script>
|
|
41
|
-
*/
|
|
42
|
-
interface PurchaseLineItem {
|
|
43
|
-
bundleGid: string;
|
|
44
|
-
bundleType: string;
|
|
45
|
-
price: number;
|
|
46
|
-
quantity: number;
|
|
47
|
-
}
|
|
48
|
-
interface TrackPurchaseInput {
|
|
49
|
-
shopDomain: string;
|
|
50
|
-
orderId: string;
|
|
51
|
-
lineItems: PurchaseLineItem[];
|
|
52
|
-
appUrl?: string;
|
|
53
|
-
}
|
|
54
|
-
declare function trackPurchase(input: TrackPurchaseInput): void;
|
|
55
|
-
|
|
56
|
-
export { LimeBundleElement, trackPurchase };
|
|
31
|
+
export { LimeBundleElement };
|
package/dist/index.js
CHANGED
|
@@ -2,18 +2,19 @@
|
|
|
2
2
|
import {
|
|
3
3
|
createStorefrontClient,
|
|
4
4
|
BUNDLE_METAOBJECT_QUERY,
|
|
5
|
+
SHOP_CUSTOM_CSS_QUERY,
|
|
5
6
|
parseMetaobjectBundle,
|
|
6
|
-
detectCartApi,
|
|
7
|
-
createAjaxCartApi,
|
|
8
|
-
createStorefrontCartApi,
|
|
9
7
|
observeImpression,
|
|
10
8
|
reportImpression,
|
|
11
|
-
reportAddToCart
|
|
9
|
+
reportAddToCart,
|
|
10
|
+
injectCustomCss
|
|
12
11
|
} from "@lime-bundles/core";
|
|
13
12
|
|
|
14
13
|
// src/renderers/fixed.ts
|
|
15
|
-
import {
|
|
16
|
-
|
|
14
|
+
import {
|
|
15
|
+
formatMoney
|
|
16
|
+
} from "@lime-bundles/core";
|
|
17
|
+
function renderFixedBundle(container, bundle, onAddToCart) {
|
|
17
18
|
const currency = bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? "USD";
|
|
18
19
|
const title = document.createElement("h3");
|
|
19
20
|
title.className = "lb-bundle__title";
|
|
@@ -54,23 +55,20 @@ function renderFixedBundle(container, bundle, addToCart) {
|
|
|
54
55
|
button.className = "lb-bundle__cta";
|
|
55
56
|
button.textContent = bundle.widgetConfig.ctaText ?? "Add Bundle to Cart";
|
|
56
57
|
button.setAttribute("part", "button");
|
|
57
|
-
button.addEventListener("click",
|
|
58
|
-
|
|
59
|
-
button.textContent = "Adding...";
|
|
60
|
-
const items = bundle.products.filter((p) => p.variants.nodes.some((v) => v.availableForSale)).map((p) => {
|
|
58
|
+
button.addEventListener("click", () => {
|
|
59
|
+
const lines = bundle.products.filter((p) => p.variants.nodes.some((v) => v.availableForSale)).map((p) => {
|
|
61
60
|
const variant = p.variants.nodes.find((v) => v.availableForSale);
|
|
62
|
-
return {
|
|
61
|
+
return {
|
|
62
|
+
merchandiseId: variant.id,
|
|
63
|
+
quantity: 1,
|
|
64
|
+
attributes: [
|
|
65
|
+
{ key: "_lime_bundle_gid", value: bundle.id },
|
|
66
|
+
{ key: "_lime_bundle_type", value: bundle.bundleType }
|
|
67
|
+
]
|
|
68
|
+
};
|
|
63
69
|
});
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
button.textContent = bundle.widgetConfig.ctaText ?? "Add Bundle to Cart";
|
|
67
|
-
if (!result.success) {
|
|
68
|
-
const error = document.createElement("p");
|
|
69
|
-
error.className = "lb-bundle__error";
|
|
70
|
-
error.textContent = result.error ?? "Failed to add to cart";
|
|
71
|
-
container.appendChild(error);
|
|
72
|
-
setTimeout(() => error.remove(), 5e3);
|
|
73
|
-
}
|
|
70
|
+
if (lines.length === 0) return;
|
|
71
|
+
onAddToCart(lines);
|
|
74
72
|
});
|
|
75
73
|
container.appendChild(button);
|
|
76
74
|
}
|
|
@@ -81,8 +79,11 @@ function escapeHtml(str) {
|
|
|
81
79
|
}
|
|
82
80
|
|
|
83
81
|
// src/renderers/mix-match.ts
|
|
84
|
-
import {
|
|
85
|
-
|
|
82
|
+
import {
|
|
83
|
+
formatMoney as formatMoney2,
|
|
84
|
+
validateQuantity
|
|
85
|
+
} from "@lime-bundles/core";
|
|
86
|
+
function renderMixMatchBundle(container, bundle, onAddToCart) {
|
|
86
87
|
const currency = bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? "USD";
|
|
87
88
|
const selections = /* @__PURE__ */ new Map();
|
|
88
89
|
const title = document.createElement("h3");
|
|
@@ -146,29 +147,31 @@ function renderMixMatchBundle(container, bundle, addToCart) {
|
|
|
146
147
|
button.disabled = true;
|
|
147
148
|
container.appendChild(button);
|
|
148
149
|
function updateCta() {
|
|
149
|
-
const total = Array.from(selections.values()).reduce(
|
|
150
|
-
|
|
150
|
+
const total = Array.from(selections.values()).reduce(
|
|
151
|
+
(s, v) => s + v.quantity,
|
|
152
|
+
0
|
|
153
|
+
);
|
|
154
|
+
const validation = validateQuantity(
|
|
155
|
+
total,
|
|
156
|
+
bundle.minQuantity,
|
|
157
|
+
bundle.maxQuantity
|
|
158
|
+
);
|
|
151
159
|
button.disabled = !validation.valid;
|
|
152
160
|
button.textContent = bundle.widgetConfig.ctaText ?? `Add ${total} Items to Cart`;
|
|
153
161
|
validationEl.textContent = validation.message ?? "";
|
|
154
162
|
}
|
|
155
163
|
updateCta();
|
|
156
|
-
button.addEventListener("click",
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
164
|
+
button.addEventListener("click", () => {
|
|
165
|
+
const lines = Array.from(selections.values()).map((s) => ({
|
|
166
|
+
merchandiseId: s.variantId,
|
|
167
|
+
quantity: s.quantity,
|
|
168
|
+
attributes: [
|
|
169
|
+
{ key: "_lime_bundle_gid", value: bundle.id },
|
|
170
|
+
{ key: "_lime_bundle_type", value: bundle.bundleType }
|
|
171
|
+
]
|
|
162
172
|
}));
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
if (!result.success) {
|
|
166
|
-
const error = document.createElement("p");
|
|
167
|
-
error.className = "lb-bundle__error";
|
|
168
|
-
error.textContent = result.error ?? "Failed to add to cart";
|
|
169
|
-
container.appendChild(error);
|
|
170
|
-
setTimeout(() => error.remove(), 5e3);
|
|
171
|
-
}
|
|
173
|
+
if (lines.length === 0) return;
|
|
174
|
+
onAddToCart(lines);
|
|
172
175
|
});
|
|
173
176
|
}
|
|
174
177
|
function escapeHtml2(str) {
|
|
@@ -178,8 +181,11 @@ function escapeHtml2(str) {
|
|
|
178
181
|
}
|
|
179
182
|
|
|
180
183
|
// src/renderers/volume.ts
|
|
181
|
-
import {
|
|
182
|
-
|
|
184
|
+
import {
|
|
185
|
+
formatMoney as formatMoney3,
|
|
186
|
+
calculateTierSavings
|
|
187
|
+
} from "@lime-bundles/core";
|
|
188
|
+
function renderVolumeBundle(container, bundle, onAddToCart) {
|
|
183
189
|
const product = bundle.products[0];
|
|
184
190
|
if (!product) return;
|
|
185
191
|
const basePrice = parseFloat(product.priceRange.minVariantPrice.amount);
|
|
@@ -239,7 +245,11 @@ function renderVolumeBundle(container, bundle, addToCart) {
|
|
|
239
245
|
button.setAttribute("part", "button");
|
|
240
246
|
container.appendChild(button);
|
|
241
247
|
function updateTiers() {
|
|
242
|
-
const savings = calculateTierSavings(
|
|
248
|
+
const savings = calculateTierSavings(
|
|
249
|
+
bundle.volumeTiers,
|
|
250
|
+
basePrice,
|
|
251
|
+
quantity
|
|
252
|
+
);
|
|
243
253
|
tiersDiv.innerHTML = "";
|
|
244
254
|
for (const ts of savings) {
|
|
245
255
|
const row = document.createElement("div");
|
|
@@ -275,22 +285,19 @@ function renderVolumeBundle(container, bundle, addToCart) {
|
|
|
275
285
|
updateTiers();
|
|
276
286
|
}
|
|
277
287
|
});
|
|
278
|
-
button.addEventListener("click",
|
|
288
|
+
button.addEventListener("click", () => {
|
|
279
289
|
const variant = product.variants.nodes.find((v) => v.availableForSale);
|
|
280
290
|
if (!variant) return;
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
container.appendChild(error);
|
|
292
|
-
setTimeout(() => error.remove(), 5e3);
|
|
293
|
-
}
|
|
291
|
+
onAddToCart([
|
|
292
|
+
{
|
|
293
|
+
merchandiseId: variant.id,
|
|
294
|
+
quantity,
|
|
295
|
+
attributes: [
|
|
296
|
+
{ key: "_lime_bundle_gid", value: bundle.id },
|
|
297
|
+
{ key: "_lime_bundle_type", value: bundle.bundleType }
|
|
298
|
+
]
|
|
299
|
+
}
|
|
300
|
+
]);
|
|
294
301
|
});
|
|
295
302
|
}
|
|
296
303
|
function escapeHtml3(str) {
|
|
@@ -371,7 +378,6 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
371
378
|
"shop-domain",
|
|
372
379
|
"storefront-token",
|
|
373
380
|
"bundle-gid",
|
|
374
|
-
"cart-id",
|
|
375
381
|
"app-url",
|
|
376
382
|
"analytics",
|
|
377
383
|
"locale"
|
|
@@ -392,7 +398,6 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
392
398
|
this.abortController?.abort();
|
|
393
399
|
this.teardownImpression();
|
|
394
400
|
}
|
|
395
|
-
/** Clean up stale bundle state and active impression observer. */
|
|
396
401
|
teardownImpression() {
|
|
397
402
|
this.impressionCleanup?.();
|
|
398
403
|
this.impressionCleanup = null;
|
|
@@ -414,9 +419,6 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
414
419
|
get bundleGid() {
|
|
415
420
|
return this.getAttribute("bundle-gid") ?? "";
|
|
416
421
|
}
|
|
417
|
-
get cartId() {
|
|
418
|
-
return this.getAttribute("cart-id") ?? void 0;
|
|
419
|
-
}
|
|
420
422
|
get appUrl() {
|
|
421
423
|
return this.getAttribute("app-url") ?? "";
|
|
422
424
|
}
|
|
@@ -425,7 +427,9 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
425
427
|
}
|
|
426
428
|
async fetchBundle() {
|
|
427
429
|
if (!this.shopDomain || !this.storefrontToken || !this.bundleGid) {
|
|
428
|
-
this.renderError(
|
|
430
|
+
this.renderError(
|
|
431
|
+
"Missing required attributes: shop-domain, storefront-token, bundle-gid"
|
|
432
|
+
);
|
|
429
433
|
return;
|
|
430
434
|
}
|
|
431
435
|
this.abortController?.abort();
|
|
@@ -437,26 +441,37 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
437
441
|
shopDomain: this.shopDomain,
|
|
438
442
|
accessToken: this.storefrontToken
|
|
439
443
|
});
|
|
440
|
-
const
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
+
const [bundleData, cssData] = await Promise.all([
|
|
445
|
+
client.query(
|
|
446
|
+
BUNDLE_METAOBJECT_QUERY,
|
|
447
|
+
{ id: this.bundleGid },
|
|
448
|
+
{ signal: controller.signal }
|
|
449
|
+
),
|
|
450
|
+
client.query(
|
|
451
|
+
SHOP_CUSTOM_CSS_QUERY,
|
|
452
|
+
void 0,
|
|
453
|
+
{ signal: controller.signal }
|
|
454
|
+
).catch(() => null)
|
|
455
|
+
]);
|
|
444
456
|
if (controller.signal.aborted) return;
|
|
445
|
-
if (!
|
|
457
|
+
if (!bundleData.metaobject) {
|
|
446
458
|
this.bundle = null;
|
|
447
459
|
this.teardownImpression();
|
|
448
460
|
this.renderError("Bundle not found");
|
|
449
461
|
return;
|
|
450
462
|
}
|
|
451
463
|
this.bundle = parseMetaobjectBundle(
|
|
452
|
-
|
|
453
|
-
|
|
464
|
+
bundleData.metaobject.id,
|
|
465
|
+
bundleData.metaobject.fields
|
|
454
466
|
);
|
|
455
467
|
if (!this.bundle) {
|
|
456
468
|
this.teardownImpression();
|
|
457
469
|
this.renderError("Bundle is not active or has expired");
|
|
458
470
|
return;
|
|
459
471
|
}
|
|
472
|
+
if (cssData?.shop?.metafield?.value) {
|
|
473
|
+
injectCustomCss(this.shopDomain, cssData.shop.metafield.value);
|
|
474
|
+
}
|
|
460
475
|
this.renderBundle();
|
|
461
476
|
this.setupImpression();
|
|
462
477
|
} catch (err) {
|
|
@@ -468,73 +483,70 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
468
483
|
);
|
|
469
484
|
}
|
|
470
485
|
}
|
|
486
|
+
/**
|
|
487
|
+
* Dispatch add-to-cart for merchant handling. Returns true — the widget
|
|
488
|
+
* reports success optimistically. If the merchant's cart mutation fails,
|
|
489
|
+
* they're responsible for surfacing that error in their own UI.
|
|
490
|
+
*/
|
|
491
|
+
dispatchAddToCart = (lines) => {
|
|
492
|
+
this.dispatchEvent(
|
|
493
|
+
new CustomEvent("lime-bundle:add-to-cart", {
|
|
494
|
+
detail: { lines },
|
|
495
|
+
bubbles: true,
|
|
496
|
+
composed: true
|
|
497
|
+
})
|
|
498
|
+
);
|
|
499
|
+
if (this.analyticsEnabled && this.appUrl && this.bundle) {
|
|
500
|
+
const quantity = lines.reduce((sum, l) => sum + l.quantity, 0);
|
|
501
|
+
const totalPrice = lines.reduce((sum, line) => {
|
|
502
|
+
const product = this.bundle.products.find(
|
|
503
|
+
(p) => p.variants.nodes.some((v) => v.id === line.merchandiseId)
|
|
504
|
+
);
|
|
505
|
+
const variant = product?.variants.nodes.find(
|
|
506
|
+
(v) => v.id === line.merchandiseId
|
|
507
|
+
);
|
|
508
|
+
const price = variant ? parseFloat(variant.price.amount) : 0;
|
|
509
|
+
return sum + price * line.quantity;
|
|
510
|
+
}, 0);
|
|
511
|
+
reportAddToCart(
|
|
512
|
+
{ shopDomain: this.shopDomain, appUrl: this.appUrl },
|
|
513
|
+
{
|
|
514
|
+
bundleGid: this.bundleGid,
|
|
515
|
+
bundleType: this.bundle.bundleType,
|
|
516
|
+
productId: this.bundle.products[0]?.id ?? "",
|
|
517
|
+
quantity,
|
|
518
|
+
totalPrice: Math.round(totalPrice * 100) / 100
|
|
519
|
+
}
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
};
|
|
471
523
|
renderBundle() {
|
|
472
524
|
if (!this.bundle) return;
|
|
473
525
|
const container = document.createElement("div");
|
|
474
526
|
container.className = "lb-bundle";
|
|
475
527
|
container.setAttribute("role", "region");
|
|
476
528
|
container.setAttribute("aria-label", this.bundle.title);
|
|
477
|
-
const addToCart = async (items) => {
|
|
478
|
-
const apiType = detectCartApi();
|
|
479
|
-
const cart = apiType === "ajax" ? createAjaxCartApi(this.bundleGid, this.bundle.bundleType) : createStorefrontCartApi(
|
|
480
|
-
createStorefrontClient({
|
|
481
|
-
shopDomain: this.shopDomain,
|
|
482
|
-
accessToken: this.storefrontToken
|
|
483
|
-
}),
|
|
484
|
-
this.bundleGid,
|
|
485
|
-
this.bundle.bundleType,
|
|
486
|
-
this.cartId
|
|
487
|
-
);
|
|
488
|
-
let result;
|
|
489
|
-
try {
|
|
490
|
-
result = await cart.addLines(items);
|
|
491
|
-
} catch (err) {
|
|
492
|
-
result = {
|
|
493
|
-
success: false,
|
|
494
|
-
error: err instanceof Error ? err.message : "Cart add failed"
|
|
495
|
-
};
|
|
496
|
-
}
|
|
497
|
-
if (result.success) {
|
|
498
|
-
this.dispatchEvent(
|
|
499
|
-
new CustomEvent("lime-bundle:add-to-cart", {
|
|
500
|
-
detail: { items, cartId: result.cartId },
|
|
501
|
-
bubbles: true,
|
|
502
|
-
composed: true
|
|
503
|
-
})
|
|
504
|
-
);
|
|
505
|
-
if (this.analyticsEnabled && this.appUrl) {
|
|
506
|
-
const quantity = items.reduce((sum, i) => sum + i.quantity, 0);
|
|
507
|
-
const totalPrice = items.reduce((sum, item) => {
|
|
508
|
-
const product = this.bundle.products.find(
|
|
509
|
-
(p) => p.variants.nodes.some((v) => v.id === item.variantId)
|
|
510
|
-
);
|
|
511
|
-
const variant = product?.variants.nodes.find((v) => v.id === item.variantId);
|
|
512
|
-
const price = variant ? parseFloat(variant.price.amount) : 0;
|
|
513
|
-
return sum + price * item.quantity;
|
|
514
|
-
}, 0);
|
|
515
|
-
reportAddToCart(
|
|
516
|
-
{ shopDomain: this.shopDomain, appUrl: this.appUrl },
|
|
517
|
-
{
|
|
518
|
-
bundleGid: this.bundleGid,
|
|
519
|
-
bundleType: this.bundle.bundleType,
|
|
520
|
-
productId: this.bundle.products[0]?.id ?? "",
|
|
521
|
-
quantity,
|
|
522
|
-
totalPrice: Math.round(totalPrice * 100) / 100
|
|
523
|
-
}
|
|
524
|
-
);
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
return result;
|
|
528
|
-
};
|
|
529
529
|
switch (this.bundle.bundleType) {
|
|
530
530
|
case "fixed":
|
|
531
|
-
renderFixedBundle(
|
|
531
|
+
renderFixedBundle(
|
|
532
|
+
container,
|
|
533
|
+
this.bundle,
|
|
534
|
+
this.dispatchAddToCart
|
|
535
|
+
);
|
|
532
536
|
break;
|
|
533
537
|
case "mix_match":
|
|
534
|
-
renderMixMatchBundle(
|
|
538
|
+
renderMixMatchBundle(
|
|
539
|
+
container,
|
|
540
|
+
this.bundle,
|
|
541
|
+
this.dispatchAddToCart
|
|
542
|
+
);
|
|
535
543
|
break;
|
|
536
544
|
case "volume":
|
|
537
|
-
renderVolumeBundle(
|
|
545
|
+
renderVolumeBundle(
|
|
546
|
+
container,
|
|
547
|
+
this.bundle,
|
|
548
|
+
this.dispatchAddToCart
|
|
549
|
+
);
|
|
538
550
|
break;
|
|
539
551
|
}
|
|
540
552
|
this.shadow.innerHTML = "";
|
|
@@ -590,65 +602,11 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
590
602
|
}
|
|
591
603
|
};
|
|
592
604
|
|
|
593
|
-
// src/thankyou/index.ts
|
|
594
|
-
var reportedPurchases = /* @__PURE__ */ new Set();
|
|
595
|
-
function trackPurchase(input) {
|
|
596
|
-
const appUrl = input.appUrl ?? `https://${input.shopDomain}`;
|
|
597
|
-
const bundleMap = /* @__PURE__ */ new Map();
|
|
598
|
-
for (const item of input.lineItems) {
|
|
599
|
-
if (!item.bundleGid) continue;
|
|
600
|
-
const existing = bundleMap.get(item.bundleGid);
|
|
601
|
-
if (existing) {
|
|
602
|
-
existing.revenue += item.price * item.quantity;
|
|
603
|
-
existing.lineItemCount += 1;
|
|
604
|
-
} else {
|
|
605
|
-
bundleMap.set(item.bundleGid, {
|
|
606
|
-
bundleType: item.bundleType,
|
|
607
|
-
revenue: item.price * item.quantity,
|
|
608
|
-
lineItemCount: 1
|
|
609
|
-
});
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
for (const [bundleGid, data] of bundleMap) {
|
|
613
|
-
const dedupKey = `${input.orderId}:${bundleGid}`;
|
|
614
|
-
if (reportedPurchases.has(dedupKey)) continue;
|
|
615
|
-
reportedPurchases.add(dedupKey);
|
|
616
|
-
const payload = {
|
|
617
|
-
shopDomain: input.shopDomain,
|
|
618
|
-
eventType: "bundle_purchased",
|
|
619
|
-
bundleGid,
|
|
620
|
-
bundleType: data.bundleType,
|
|
621
|
-
orderId: input.orderId,
|
|
622
|
-
revenue: Math.round(data.revenue * 100) / 100,
|
|
623
|
-
lineItemCount: data.lineItemCount,
|
|
624
|
-
occurredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
625
|
-
};
|
|
626
|
-
const url = `${appUrl}/api/analytics`;
|
|
627
|
-
const body = JSON.stringify(payload);
|
|
628
|
-
try {
|
|
629
|
-
fetch(url, {
|
|
630
|
-
method: "POST",
|
|
631
|
-
headers: { "Content-Type": "application/json" },
|
|
632
|
-
body
|
|
633
|
-
}).catch(() => {
|
|
634
|
-
if (typeof navigator !== "undefined" && navigator.sendBeacon) {
|
|
635
|
-
navigator.sendBeacon(url, body);
|
|
636
|
-
}
|
|
637
|
-
});
|
|
638
|
-
} catch {
|
|
639
|
-
if (typeof navigator !== "undefined" && navigator.sendBeacon) {
|
|
640
|
-
navigator.sendBeacon(url, body);
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
|
|
646
605
|
// src/index.ts
|
|
647
606
|
if (typeof customElements !== "undefined" && !customElements.get("lime-bundle")) {
|
|
648
607
|
customElements.define("lime-bundle", LimeBundleElement);
|
|
649
608
|
}
|
|
650
609
|
export {
|
|
651
|
-
LimeBundleElement
|
|
652
|
-
trackPurchase
|
|
610
|
+
LimeBundleElement
|
|
653
611
|
};
|
|
654
612
|
//# sourceMappingURL=index.js.map
|