@cshah18/sdk 3.0.0 → 3.0.1
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/cobuy-sdk.esm.js +320 -40
- package/dist/cobuy-sdk.esm.js.map +1 -1
- package/dist/cobuy-sdk.umd.js +320 -40
- package/dist/cobuy-sdk.umd.js.map +1 -1
- package/dist/types/core/api-client.d.ts +36 -1
- package/dist/types/core/cobuy.d.ts +54 -1
- package/dist/types/core/endpoints.d.ts +3 -0
- package/dist/types/core/types.d.ts +43 -8
- package/dist/types/ui/lobby/lobby-modal.d.ts +1 -2
- package/dist/types/ui/widget/widget-root.d.ts +2 -1
- package/package.json +1 -1
package/dist/cobuy-sdk.esm.js
CHANGED
|
@@ -1305,6 +1305,21 @@ class LobbyModal {
|
|
|
1305
1305
|
this.socketListenerRegistered = false;
|
|
1306
1306
|
this.currentGroupId = null;
|
|
1307
1307
|
this.shareOverlay = null;
|
|
1308
|
+
/**
|
|
1309
|
+
* Unsubscribe from socket events - testing out flow will remove once we have conviction
|
|
1310
|
+
*/
|
|
1311
|
+
// private unsubscribeFromSocketEvents(): void {
|
|
1312
|
+
// if (typeof window === "undefined" || !this.socketListenerRegistered) {
|
|
1313
|
+
// return;
|
|
1314
|
+
// }
|
|
1315
|
+
// window.removeEventListener("group:fulfilled", this.handleSocketGroupUpdate as EventListener);
|
|
1316
|
+
// window.removeEventListener(
|
|
1317
|
+
// "group:member:joined",
|
|
1318
|
+
// this.handleSocketGroupUpdate as EventListener,
|
|
1319
|
+
// );
|
|
1320
|
+
// window.removeEventListener("group:created", this.handleSocketGroupUpdate as EventListener);
|
|
1321
|
+
// this.socketListenerRegistered = false;
|
|
1322
|
+
// }
|
|
1308
1323
|
/**
|
|
1309
1324
|
* Handle socket group update events
|
|
1310
1325
|
*/
|
|
@@ -2326,11 +2341,11 @@ class LobbyModal {
|
|
|
2326
2341
|
// Stop timers and animations
|
|
2327
2342
|
this.stopTimer();
|
|
2328
2343
|
this.stopActivityAnimation();
|
|
2329
|
-
// Unsubscribe from socket events and group
|
|
2330
|
-
this.unsubscribeFromSocketEvents();
|
|
2331
|
-
if (this.socketManager && this.currentGroupId) {
|
|
2332
|
-
|
|
2333
|
-
}
|
|
2344
|
+
// // Unsubscribe from socket events and group - testing out flow will remove once we have conviction
|
|
2345
|
+
// this.unsubscribeFromSocketEvents();
|
|
2346
|
+
// if (this.socketManager && this.currentGroupId) {
|
|
2347
|
+
// this.socketManager.unsubscribeFromGroup(this.currentGroupId);
|
|
2348
|
+
// }
|
|
2334
2349
|
// Remove modal from DOM
|
|
2335
2350
|
document.body.removeChild(this.modalElement);
|
|
2336
2351
|
this.modalElement = null;
|
|
@@ -2445,18 +2460,6 @@ class LobbyModal {
|
|
|
2445
2460
|
window.addEventListener("group:created", this.handleSocketGroupUpdate);
|
|
2446
2461
|
this.socketListenerRegistered = true;
|
|
2447
2462
|
}
|
|
2448
|
-
/**
|
|
2449
|
-
* Unsubscribe from socket events
|
|
2450
|
-
*/
|
|
2451
|
-
unsubscribeFromSocketEvents() {
|
|
2452
|
-
if (typeof window === "undefined" || !this.socketListenerRegistered) {
|
|
2453
|
-
return;
|
|
2454
|
-
}
|
|
2455
|
-
window.removeEventListener("group:fulfilled", this.handleSocketGroupUpdate);
|
|
2456
|
-
window.removeEventListener("group:member:joined", this.handleSocketGroupUpdate);
|
|
2457
|
-
window.removeEventListener("group:created", this.handleSocketGroupUpdate);
|
|
2458
|
-
this.socketListenerRegistered = false;
|
|
2459
|
-
}
|
|
2460
2463
|
/**
|
|
2461
2464
|
* Create activity item from socket event data
|
|
2462
2465
|
*/
|
|
@@ -2582,9 +2585,9 @@ class WidgetRoot {
|
|
|
2582
2585
|
this.groupListModal = null;
|
|
2583
2586
|
this.lastGroupDataRefreshTime = 0;
|
|
2584
2587
|
this.GROUP_REFRESH_DEBOUNCE = 1000; // 1 second min between refreshes
|
|
2588
|
+
this.groupExpiryRefreshTriggered = false; // Track if expiry refresh already triggered for current group
|
|
2585
2589
|
/** Handle backend fulfillment notifications */
|
|
2586
2590
|
this.handleGroupFulfilledEvent = (event) => {
|
|
2587
|
-
console.log("CHIRAG");
|
|
2588
2591
|
const detail = event.detail;
|
|
2589
2592
|
if (!detail || !detail.productId) {
|
|
2590
2593
|
return;
|
|
@@ -2596,9 +2599,10 @@ class WidgetRoot {
|
|
|
2596
2599
|
};
|
|
2597
2600
|
/** Handle realtime group creation/join events by refreshing group UI */
|
|
2598
2601
|
this.handleGroupUpdatedEvent = (event) => {
|
|
2602
|
+
var _a;
|
|
2599
2603
|
const detail = event.detail || {};
|
|
2600
|
-
const productId = detail.
|
|
2601
|
-
const groupId = detail.
|
|
2604
|
+
const productId = detail.product_id;
|
|
2605
|
+
const groupId = (_a = detail.group) === null || _a === void 0 ? void 0 : _a.id;
|
|
2602
2606
|
if (productId && this.currentProductId && productId !== this.currentProductId) {
|
|
2603
2607
|
return;
|
|
2604
2608
|
}
|
|
@@ -2864,14 +2868,10 @@ class WidgetRoot {
|
|
|
2864
2868
|
footer.style.display = "flex";
|
|
2865
2869
|
footer.style.justifyContent = "flex-end";
|
|
2866
2870
|
footer.style.alignItems = "center";
|
|
2867
|
-
const viewAllLink = this.createInlineViewAllLink();
|
|
2868
|
-
if (viewAllLink) {
|
|
2869
|
-
footer.appendChild(viewAllLink);
|
|
2870
|
-
}
|
|
2871
2871
|
root.appendChild(footer);
|
|
2872
2872
|
return root;
|
|
2873
2873
|
}
|
|
2874
|
-
/** Update countdown text */
|
|
2874
|
+
/** Update countdown text and trigger refresh when group expires */
|
|
2875
2875
|
updateTimer(el, expiryMs, remaining) {
|
|
2876
2876
|
const now = Date.now();
|
|
2877
2877
|
const diff = Math.max(0, Math.floor((expiryMs - now) / 1000));
|
|
@@ -2885,6 +2885,12 @@ class WidgetRoot {
|
|
|
2885
2885
|
else {
|
|
2886
2886
|
el.textContent = "✨ Discount activated!";
|
|
2887
2887
|
el.classList.add("activated");
|
|
2888
|
+
// Trigger group refresh only once when expiry is reached, regardless of modal state
|
|
2889
|
+
if (!this.groupExpiryRefreshTriggered && diff <= 0) {
|
|
2890
|
+
this.groupExpiryRefreshTriggered = true;
|
|
2891
|
+
this.logger.info("[Expiry] Group expired, refreshing group data");
|
|
2892
|
+
void this.refreshGroupDataFromRealtime();
|
|
2893
|
+
}
|
|
2888
2894
|
}
|
|
2889
2895
|
}
|
|
2890
2896
|
/** Build and attach the shared "View all Groups" link section */
|
|
@@ -2996,6 +3002,7 @@ class WidgetRoot {
|
|
|
2996
3002
|
this.frozenReward = null;
|
|
2997
3003
|
this.currentGroupId = null;
|
|
2998
3004
|
this.currentRewardData = null;
|
|
3005
|
+
this.groupExpiryRefreshTriggered = false; // Reset expiry refresh flag for new render
|
|
2999
3006
|
// Listen for realtime fulfillment updates once per page
|
|
3000
3007
|
this.subscribeToSocketEvents();
|
|
3001
3008
|
// Host safety + idempotency markers
|
|
@@ -3410,7 +3417,6 @@ class WidgetRoot {
|
|
|
3410
3417
|
}
|
|
3411
3418
|
}
|
|
3412
3419
|
createWidget(rewardData, container, options) {
|
|
3413
|
-
var _a, _b;
|
|
3414
3420
|
const isFulfilled = this.groupFulfilled;
|
|
3415
3421
|
const activeReward = this.frozenReward || (rewardData === null || rewardData === void 0 ? void 0 : rewardData.reward) || null;
|
|
3416
3422
|
const wrapper = document.createElement("div");
|
|
@@ -3460,7 +3466,7 @@ class WidgetRoot {
|
|
|
3460
3466
|
rewardLine.setAttribute("aria-label", rewardText ? `Reward locked in: ${rewardText}` : "Reward available for this group");
|
|
3461
3467
|
rewardLine.title = rewardLine.textContent;
|
|
3462
3468
|
}
|
|
3463
|
-
else if (
|
|
3469
|
+
else if (activeReward) {
|
|
3464
3470
|
const rewardText = this.formatRewardText(activeReward);
|
|
3465
3471
|
rewardLine.textContent = rewardText
|
|
3466
3472
|
? `Save up to ${rewardText} with CoBuy`
|
|
@@ -3468,12 +3474,6 @@ class WidgetRoot {
|
|
|
3468
3474
|
rewardLine.setAttribute("aria-label", `Eligible for CoBuy reward: ${rewardLine.textContent}`);
|
|
3469
3475
|
rewardLine.title = rewardLine.textContent;
|
|
3470
3476
|
}
|
|
3471
|
-
else if (rewardData && !((_b = rewardData.eligibility) === null || _b === void 0 ? void 0 : _b.isEligible)) {
|
|
3472
|
-
rewardLine.textContent = "Join with CoBuy to unlock rewards";
|
|
3473
|
-
rewardLine.setAttribute("aria-label", "Join with CoBuy to unlock rewards");
|
|
3474
|
-
rewardLine.title = "Join with CoBuy to unlock rewards";
|
|
3475
|
-
rewardLine.style.color = "#6b7280";
|
|
3476
|
-
}
|
|
3477
3477
|
else {
|
|
3478
3478
|
rewardLine.textContent = "CoBuy offer loading or unavailable";
|
|
3479
3479
|
rewardLine.setAttribute("aria-label", "CoBuy offer loading or unavailable");
|
|
@@ -3877,7 +3877,6 @@ class WidgetRoot {
|
|
|
3877
3877
|
* Format reward text for rendering in external container
|
|
3878
3878
|
*/
|
|
3879
3879
|
formatRewardForContainer(rewardData) {
|
|
3880
|
-
var _a;
|
|
3881
3880
|
const reward = this.frozenReward || (rewardData === null || rewardData === void 0 ? void 0 : rewardData.reward);
|
|
3882
3881
|
if (this.groupFulfilled) {
|
|
3883
3882
|
const rewardText = this.formatRewardText(reward);
|
|
@@ -3887,12 +3886,7 @@ class WidgetRoot {
|
|
|
3887
3886
|
return "Join with CoBuy to unlock rewards";
|
|
3888
3887
|
}
|
|
3889
3888
|
const rewardText = this.formatRewardText(reward);
|
|
3890
|
-
|
|
3891
|
-
return rewardText ? `Save up to ${rewardText} with CoBuy` : "CoBuy reward available";
|
|
3892
|
-
}
|
|
3893
|
-
else {
|
|
3894
|
-
return "Join with CoBuy to unlock rewards";
|
|
3895
|
-
}
|
|
3889
|
+
return rewardText ? `Save up to ${rewardText} with CoBuy` : "CoBuy reward available";
|
|
3896
3890
|
}
|
|
3897
3891
|
}
|
|
3898
3892
|
|
|
@@ -3908,6 +3902,9 @@ const API_ENDPOINTS = {
|
|
|
3908
3902
|
GROUP_CREATE_AND_JOIN: "/v1/sdk/groups/new/join",
|
|
3909
3903
|
PRODUCT_ACTIVE_GROUPS: "/v1/sdk/products/:productId/groups/active",
|
|
3910
3904
|
GROUP_INVITE: "/v1/sdk/groups/:groupId/invite",
|
|
3905
|
+
GROUP_CHECKOUT_PREPARE: "/v1/sdk/groups/:groupId/checkout/prepare",
|
|
3906
|
+
GROUP_CHECKOUT_VALIDATE: "/v1/sdk/groups/:groupId/checkout/validate",
|
|
3907
|
+
GROUP_CHECKOUT_CONFIRM: "/v1/sdk/groups/:groupId/checkout/confirm",
|
|
3911
3908
|
};
|
|
3912
3909
|
/**
|
|
3913
3910
|
* Build full API URL from base URL and endpoint path
|
|
@@ -4362,6 +4359,100 @@ class ApiClient {
|
|
|
4362
4359
|
},
|
|
4363
4360
|
};
|
|
4364
4361
|
}
|
|
4362
|
+
/**
|
|
4363
|
+
* Prepare checkout for a group
|
|
4364
|
+
*
|
|
4365
|
+
* Signals the backend that the user is proceeding to checkout for a specific group.
|
|
4366
|
+
* This allows the backend to prepare order data, lock pricing, and track conversion.
|
|
4367
|
+
* Returns a checkout reference to be used in subsequent validate and confirm calls.
|
|
4368
|
+
*
|
|
4369
|
+
* @param groupId - The group ID to prepare checkout for
|
|
4370
|
+
* @returns Promise with success status and checkout reference
|
|
4371
|
+
*/
|
|
4372
|
+
async prepareCheckout(groupId) {
|
|
4373
|
+
var _a, _b;
|
|
4374
|
+
const endpoint = buildApiUrl("", API_ENDPOINTS.GROUP_CHECKOUT_PREPARE, { groupId });
|
|
4375
|
+
this.logger.info(`Preparing checkout for group: ${groupId}`);
|
|
4376
|
+
const response = await this.post(endpoint);
|
|
4377
|
+
if (response.success && ((_b = (_a = response.data) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.checkout_ref)) {
|
|
4378
|
+
this.logger.info(`Checkout prepared successfully with ref: ${response.data.data.checkout_ref}`);
|
|
4379
|
+
return {
|
|
4380
|
+
success: true,
|
|
4381
|
+
data: {
|
|
4382
|
+
checkout_ref: response.data.data.checkout_ref,
|
|
4383
|
+
},
|
|
4384
|
+
};
|
|
4385
|
+
}
|
|
4386
|
+
return {
|
|
4387
|
+
success: false,
|
|
4388
|
+
error: response.error || {
|
|
4389
|
+
message: "Failed to prepare checkout",
|
|
4390
|
+
code: "PREPARE_CHECKOUT_ERROR",
|
|
4391
|
+
},
|
|
4392
|
+
};
|
|
4393
|
+
}
|
|
4394
|
+
/**
|
|
4395
|
+
* Validate checkout for a group
|
|
4396
|
+
*
|
|
4397
|
+
* Validates the checkout reference and confirms the order can proceed.
|
|
4398
|
+
* This should be called after prepareCheckout to verify the checkout state.
|
|
4399
|
+
*
|
|
4400
|
+
* @param groupId - The group ID to validate checkout for
|
|
4401
|
+
* @param checkoutRef - The checkout reference ID from the prepare step
|
|
4402
|
+
* @returns Promise with success status
|
|
4403
|
+
*/
|
|
4404
|
+
async validateCheckout(groupId, checkoutRef) {
|
|
4405
|
+
var _a;
|
|
4406
|
+
const endpoint = buildApiUrl("", API_ENDPOINTS.GROUP_CHECKOUT_VALIDATE, { groupId });
|
|
4407
|
+
this.logger.info(`Validating checkout for group: ${groupId}`);
|
|
4408
|
+
const response = await this.post(endpoint, {
|
|
4409
|
+
checkout_ref: checkoutRef,
|
|
4410
|
+
});
|
|
4411
|
+
if (response.success) {
|
|
4412
|
+
this.logger.info("Checkout validated successfully");
|
|
4413
|
+
return {
|
|
4414
|
+
success: true,
|
|
4415
|
+
data: (_a = response.data) === null || _a === void 0 ? void 0 : _a.data,
|
|
4416
|
+
};
|
|
4417
|
+
}
|
|
4418
|
+
return {
|
|
4419
|
+
success: false,
|
|
4420
|
+
error: response.error || {
|
|
4421
|
+
message: "Failed to validate checkout",
|
|
4422
|
+
code: "VALIDATE_CHECKOUT_ERROR",
|
|
4423
|
+
},
|
|
4424
|
+
};
|
|
4425
|
+
}
|
|
4426
|
+
/**
|
|
4427
|
+
* Confirm checkout for a group
|
|
4428
|
+
*
|
|
4429
|
+
* Finalizes the checkout and confirms the order.
|
|
4430
|
+
* This should be called after validateCheckout to complete the checkout process.
|
|
4431
|
+
*
|
|
4432
|
+
* @param groupId - The group ID to confirm checkout for
|
|
4433
|
+
* @param checkoutRef - The checkout reference ID from the prepare step
|
|
4434
|
+
* @returns Promise with success status
|
|
4435
|
+
*/
|
|
4436
|
+
async confirmCheckout(groupId, checkoutRef) {
|
|
4437
|
+
const endpoint = buildApiUrl("", API_ENDPOINTS.GROUP_CHECKOUT_CONFIRM, { groupId });
|
|
4438
|
+
this.logger.info(`Confirming checkout for group: ${groupId}`);
|
|
4439
|
+
const response = await this.post(endpoint, {
|
|
4440
|
+
checkout_ref: checkoutRef,
|
|
4441
|
+
});
|
|
4442
|
+
if (response.success) {
|
|
4443
|
+
this.logger.info("Checkout confirmed successfully");
|
|
4444
|
+
return {
|
|
4445
|
+
success: true,
|
|
4446
|
+
};
|
|
4447
|
+
}
|
|
4448
|
+
return {
|
|
4449
|
+
success: false,
|
|
4450
|
+
error: response.error || {
|
|
4451
|
+
message: "Failed to confirm checkout",
|
|
4452
|
+
code: "CONFIRM_CHECKOUT_ERROR",
|
|
4453
|
+
},
|
|
4454
|
+
};
|
|
4455
|
+
}
|
|
4365
4456
|
}
|
|
4366
4457
|
|
|
4367
4458
|
/**
|
|
@@ -8756,6 +8847,7 @@ class CoBuy {
|
|
|
8756
8847
|
this.analyticsClient = null;
|
|
8757
8848
|
this.sessionId = "";
|
|
8758
8849
|
this.SESSION_STORAGE_KEY = "cobuy_sdk_session_id";
|
|
8850
|
+
this.CHECKOUT_REF_PREFIX = "cobuy_checkout_ref";
|
|
8759
8851
|
this.lobbyModal = null;
|
|
8760
8852
|
this.modals = new Map();
|
|
8761
8853
|
this.socketManager = null;
|
|
@@ -8799,12 +8891,97 @@ class CoBuy {
|
|
|
8799
8891
|
// Fallback for environments without crypto.randomUUID
|
|
8800
8892
|
return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
8801
8893
|
}
|
|
8894
|
+
/**
|
|
8895
|
+
* Store checkout reference for a product/group (session-level)
|
|
8896
|
+
* Storage key format: cobuy_checkout_ref_<sessionId>_<productId>_<groupId>
|
|
8897
|
+
*/
|
|
8898
|
+
storeCheckoutRef(productId, groupId, checkoutRef) {
|
|
8899
|
+
if (typeof window === "undefined" || !window.localStorage) {
|
|
8900
|
+
this.logger.warn("[SDK] localStorage not available, cannot store checkout reference");
|
|
8901
|
+
return;
|
|
8902
|
+
}
|
|
8903
|
+
const storageKey = `${this.CHECKOUT_REF_PREFIX}_${this.sessionId}_${productId}_${groupId}`;
|
|
8904
|
+
try {
|
|
8905
|
+
window.localStorage.setItem(storageKey, checkoutRef);
|
|
8906
|
+
this.logger.debug(`[SDK] Stored checkout reference: ${storageKey}`);
|
|
8907
|
+
}
|
|
8908
|
+
catch (e) {
|
|
8909
|
+
this.logger.warn("[SDK] Could not store checkout reference to localStorage", e);
|
|
8910
|
+
}
|
|
8911
|
+
}
|
|
8912
|
+
/**
|
|
8913
|
+
* Retrieve checkout reference for a product/group (session-level)
|
|
8914
|
+
* If groupId provided, try exact match first; otherwise fall back to any key for that product
|
|
8915
|
+
* Returns both the matched storage key and the checkout reference value (or null if not found)
|
|
8916
|
+
*/
|
|
8917
|
+
getCheckoutRef(productId, groupId) {
|
|
8918
|
+
if (typeof window === "undefined" || !window.localStorage) {
|
|
8919
|
+
return { key: null, checkoutRef: null, groupId: null };
|
|
8920
|
+
}
|
|
8921
|
+
const basePrefix = `${this.CHECKOUT_REF_PREFIX}_${this.sessionId}_${productId}`;
|
|
8922
|
+
// Try exact match if groupId supplied
|
|
8923
|
+
if (groupId) {
|
|
8924
|
+
const exactKey = `${basePrefix}_${groupId}`;
|
|
8925
|
+
const exactRef = window.localStorage.getItem(exactKey);
|
|
8926
|
+
if (exactRef) {
|
|
8927
|
+
this.logger.debug(`[SDK] Retrieved checkout reference: ${exactKey}`);
|
|
8928
|
+
return { key: exactKey, checkoutRef: exactRef, groupId };
|
|
8929
|
+
}
|
|
8930
|
+
}
|
|
8931
|
+
// Fallback: find any checkout ref for this product (ignore group)
|
|
8932
|
+
for (let i = 0; i < window.localStorage.length; i++) {
|
|
8933
|
+
const key = window.localStorage.key(i);
|
|
8934
|
+
if (key && key.startsWith(basePrefix)) {
|
|
8935
|
+
const ref = window.localStorage.getItem(key);
|
|
8936
|
+
if (ref) {
|
|
8937
|
+
this.logger.debug(`[SDK] Retrieved checkout reference via prefix: ${key}`);
|
|
8938
|
+
const parsedGroupId = key.startsWith(`${basePrefix}_`) ? key.substring(basePrefix.length + 1) : null;
|
|
8939
|
+
return { key, checkoutRef: ref, groupId: parsedGroupId };
|
|
8940
|
+
}
|
|
8941
|
+
}
|
|
8942
|
+
}
|
|
8943
|
+
return { key: null, checkoutRef: null, groupId: null };
|
|
8944
|
+
}
|
|
8802
8945
|
/**
|
|
8803
8946
|
* Get the current session ID (core SDK concept)
|
|
8804
8947
|
*/
|
|
8805
8948
|
getSessionId() {
|
|
8806
8949
|
return this.sessionId;
|
|
8807
8950
|
}
|
|
8951
|
+
/**
|
|
8952
|
+
* Prepare checkout for a group if not already prepared
|
|
8953
|
+
* Checks localStorage to prevent duplicate calls for the same product/group/session
|
|
8954
|
+
*/
|
|
8955
|
+
async prepareCheckoutIfNotDone(productId, groupId) {
|
|
8956
|
+
var _a;
|
|
8957
|
+
// Check if checkout already prepared for this product/group (session)
|
|
8958
|
+
const { checkoutRef: existingRef } = this.getCheckoutRef(productId, groupId);
|
|
8959
|
+
if (existingRef) {
|
|
8960
|
+
this.logger.debug(`[SDK] Checkout already prepared for product ${productId} (session), skipping`);
|
|
8961
|
+
return;
|
|
8962
|
+
}
|
|
8963
|
+
if (!this.apiClient) {
|
|
8964
|
+
this.logger.warn("[SDK] API client not available, cannot prepare checkout");
|
|
8965
|
+
return;
|
|
8966
|
+
}
|
|
8967
|
+
try {
|
|
8968
|
+
this.logger.info(`[SDK] Preparing checkout for product: ${productId}, group: ${groupId}`);
|
|
8969
|
+
// Call prepareCheckout to get the checkout reference
|
|
8970
|
+
const response = await this.apiClient.prepareCheckout(groupId);
|
|
8971
|
+
if (response.success && ((_a = response.data) === null || _a === void 0 ? void 0 : _a.checkout_ref)) {
|
|
8972
|
+
const checkoutRef = response.data.checkout_ref;
|
|
8973
|
+
// Store the checkout reference for this specific product and group
|
|
8974
|
+
this.storeCheckoutRef(productId, groupId, checkoutRef);
|
|
8975
|
+
this.logger.info(`[SDK] Checkout prepared and stored for ${productId}:${groupId} - Ref: ${checkoutRef}`);
|
|
8976
|
+
}
|
|
8977
|
+
else {
|
|
8978
|
+
this.logger.error("[SDK] Failed to prepare checkout", response.error);
|
|
8979
|
+
}
|
|
8980
|
+
}
|
|
8981
|
+
catch (error) {
|
|
8982
|
+
this.logger.error("[SDK] Error preparing checkout", error);
|
|
8983
|
+
}
|
|
8984
|
+
}
|
|
8808
8985
|
/**
|
|
8809
8986
|
* Initialize the SDK with configuration
|
|
8810
8987
|
*/
|
|
@@ -8865,6 +9042,21 @@ class CoBuy {
|
|
|
8865
9042
|
},
|
|
8866
9043
|
onGroupMemberJoined: (payload) => {
|
|
8867
9044
|
var _a;
|
|
9045
|
+
const group = payload.group;
|
|
9046
|
+
const productId = payload.product_id;
|
|
9047
|
+
const groupId = group === null || group === void 0 ? void 0 : group.id;
|
|
9048
|
+
const maxParticipants = group === null || group === void 0 ? void 0 : group.max_participants;
|
|
9049
|
+
const participantsCount = group === null || group === void 0 ? void 0 : group.participants_count;
|
|
9050
|
+
const status = group === null || group === void 0 ? void 0 : group.status;
|
|
9051
|
+
const isFulfilled = status === "fulfilled" ||
|
|
9052
|
+
(maxParticipants !== undefined &&
|
|
9053
|
+
participantsCount !== undefined &&
|
|
9054
|
+
participantsCount >= maxParticipants);
|
|
9055
|
+
if (isFulfilled && productId && groupId) {
|
|
9056
|
+
// Prepare checkout when group is fulfilled (if not already prepared)
|
|
9057
|
+
this.prepareCheckoutIfNotDone(productId, groupId);
|
|
9058
|
+
}
|
|
9059
|
+
// Emit user-defined callback if provided
|
|
8868
9060
|
if ((_a = config.events) === null || _a === void 0 ? void 0 : _a.onGroupMemberJoined) {
|
|
8869
9061
|
config.events.onGroupMemberJoined(payload);
|
|
8870
9062
|
}
|
|
@@ -8973,6 +9165,17 @@ class CoBuy {
|
|
|
8973
9165
|
this.lobbyModal = modal;
|
|
8974
9166
|
// Open the modal
|
|
8975
9167
|
modal.open(options.groupId);
|
|
9168
|
+
// Prepare checkout if group is fulfilled
|
|
9169
|
+
if (options.groupId) {
|
|
9170
|
+
const isFulfilled = options.status === "complete" ||
|
|
9171
|
+
options.progress === 100 ||
|
|
9172
|
+
(options.currentMembers !== undefined &&
|
|
9173
|
+
options.totalMembers !== undefined &&
|
|
9174
|
+
options.currentMembers >= options.totalMembers);
|
|
9175
|
+
if (isFulfilled) {
|
|
9176
|
+
this.prepareCheckoutIfNotDone(options.productId, options.groupId);
|
|
9177
|
+
}
|
|
9178
|
+
}
|
|
8976
9179
|
// Call callback if provided
|
|
8977
9180
|
if (options.onOpen) {
|
|
8978
9181
|
options.onOpen(options.productId);
|
|
@@ -9054,6 +9257,83 @@ class CoBuy {
|
|
|
9054
9257
|
this.logger.error("Error setting contact information", error);
|
|
9055
9258
|
}
|
|
9056
9259
|
}
|
|
9260
|
+
/**
|
|
9261
|
+
* Validate checkout for a group
|
|
9262
|
+
*
|
|
9263
|
+
* Validates the checkout reference and confirms the order can proceed.
|
|
9264
|
+
* Should be called after prepareCheckout to verify the checkout state.
|
|
9265
|
+
*
|
|
9266
|
+
* @param groupId - The group ID to validate checkout for
|
|
9267
|
+
* @param checkoutRef - The checkout reference ID from the prepare step
|
|
9268
|
+
*
|
|
9269
|
+
* @example
|
|
9270
|
+
* ```typescript
|
|
9271
|
+
* // Validate checkout for a group
|
|
9272
|
+
* await CoBuy.validateCheckout('fae238ae-7468-47e9-9eec-b6d52fe3b012', 'chk_9a6d8750-ed60-4795-a207-2abe955e8509');
|
|
9273
|
+
* ```
|
|
9274
|
+
*/
|
|
9275
|
+
async validateCheckout(groupId, checkoutRef) {
|
|
9276
|
+
if (!this.configManager.isInitialized()) {
|
|
9277
|
+
this.logger.warn("SDK not initialized, cannot validate checkout");
|
|
9278
|
+
return null;
|
|
9279
|
+
}
|
|
9280
|
+
if (!this.apiClient) {
|
|
9281
|
+
this.logger.error("API client not available");
|
|
9282
|
+
return null;
|
|
9283
|
+
}
|
|
9284
|
+
try {
|
|
9285
|
+
const response = await this.apiClient.validateCheckout(groupId, checkoutRef);
|
|
9286
|
+
if (response.success) {
|
|
9287
|
+
this.logger.info(`Checkout validated successfully for group: ${groupId}`);
|
|
9288
|
+
return response.data || null;
|
|
9289
|
+
}
|
|
9290
|
+
else {
|
|
9291
|
+
this.logger.error("Failed to validate checkout", response.error);
|
|
9292
|
+
return null;
|
|
9293
|
+
}
|
|
9294
|
+
}
|
|
9295
|
+
catch (error) {
|
|
9296
|
+
this.logger.error("Error validating checkout", error);
|
|
9297
|
+
return null;
|
|
9298
|
+
}
|
|
9299
|
+
}
|
|
9300
|
+
/**
|
|
9301
|
+
* Confirm checkout for a group
|
|
9302
|
+
*
|
|
9303
|
+
* Finalizes the checkout and confirms the order.
|
|
9304
|
+
* Should be called after validateCheckout to complete the checkout process.
|
|
9305
|
+
*
|
|
9306
|
+
* @param groupId - The group ID to confirm checkout for
|
|
9307
|
+
* @param checkoutRef - The checkout reference ID from the prepare step
|
|
9308
|
+
*
|
|
9309
|
+
* @example
|
|
9310
|
+
* ```typescript
|
|
9311
|
+
* // Confirm checkout for a group
|
|
9312
|
+
* await CoBuy.confirmCheckout('fae238ae-7468-47e9-9eec-b6d52fe3b012', 'chk_9a6d8750-ed60-4795-a207-2abe955e8509');
|
|
9313
|
+
* ```
|
|
9314
|
+
*/
|
|
9315
|
+
async confirmCheckout(groupId, checkoutRef) {
|
|
9316
|
+
if (!this.configManager.isInitialized()) {
|
|
9317
|
+
this.logger.warn("SDK not initialized, cannot confirm checkout");
|
|
9318
|
+
return;
|
|
9319
|
+
}
|
|
9320
|
+
if (!this.apiClient) {
|
|
9321
|
+
this.logger.error("API client not available");
|
|
9322
|
+
return;
|
|
9323
|
+
}
|
|
9324
|
+
try {
|
|
9325
|
+
const response = await this.apiClient.confirmCheckout(groupId, checkoutRef);
|
|
9326
|
+
if (response.success) {
|
|
9327
|
+
this.logger.info(`Checkout confirmed successfully for group: ${groupId}`);
|
|
9328
|
+
}
|
|
9329
|
+
else {
|
|
9330
|
+
this.logger.error("Failed to confirm checkout", response.error);
|
|
9331
|
+
}
|
|
9332
|
+
}
|
|
9333
|
+
catch (error) {
|
|
9334
|
+
this.logger.error("Error confirming checkout", error);
|
|
9335
|
+
}
|
|
9336
|
+
}
|
|
9057
9337
|
/**
|
|
9058
9338
|
* Get the initialized API client instance
|
|
9059
9339
|
*/
|