@cshah18/sdk 3.0.0 → 3.0.2

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.
@@ -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
- this.socketManager.unsubscribeFromGroup(this.currentGroupId);
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.productId;
2601
- const groupId = detail.groupId;
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 (((_a = rewardData === null || rewardData === void 0 ? void 0 : rewardData.eligibility) === null || _a === void 0 ? void 0 : _a.isEligible) && activeReward) {
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
- if ((_a = rewardData === null || rewardData === void 0 ? void 0 : rewardData.eligibility) === null || _a === void 0 ? void 0 : _a.isEligible) {
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
  */