@cshah18/sdk 2.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.
@@ -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,6 +2585,7 @@ 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
2591
  const detail = event.detail;
@@ -2595,9 +2599,10 @@ class WidgetRoot {
2595
2599
  };
2596
2600
  /** Handle realtime group creation/join events by refreshing group UI */
2597
2601
  this.handleGroupUpdatedEvent = (event) => {
2602
+ var _a;
2598
2603
  const detail = event.detail || {};
2599
- const productId = detail.productId;
2600
- const groupId = detail.groupId;
2604
+ const productId = detail.product_id;
2605
+ const groupId = (_a = detail.group) === null || _a === void 0 ? void 0 : _a.id;
2601
2606
  if (productId && this.currentProductId && productId !== this.currentProductId) {
2602
2607
  return;
2603
2608
  }
@@ -2863,14 +2868,10 @@ class WidgetRoot {
2863
2868
  footer.style.display = "flex";
2864
2869
  footer.style.justifyContent = "flex-end";
2865
2870
  footer.style.alignItems = "center";
2866
- const viewAllLink = this.createInlineViewAllLink();
2867
- if (viewAllLink) {
2868
- footer.appendChild(viewAllLink);
2869
- }
2870
2871
  root.appendChild(footer);
2871
2872
  return root;
2872
2873
  }
2873
- /** Update countdown text */
2874
+ /** Update countdown text and trigger refresh when group expires */
2874
2875
  updateTimer(el, expiryMs, remaining) {
2875
2876
  const now = Date.now();
2876
2877
  const diff = Math.max(0, Math.floor((expiryMs - now) / 1000));
@@ -2884,6 +2885,12 @@ class WidgetRoot {
2884
2885
  else {
2885
2886
  el.textContent = "✨ Discount activated!";
2886
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
+ }
2887
2894
  }
2888
2895
  }
2889
2896
  /** Build and attach the shared "View all Groups" link section */
@@ -2995,6 +3002,7 @@ class WidgetRoot {
2995
3002
  this.frozenReward = null;
2996
3003
  this.currentGroupId = null;
2997
3004
  this.currentRewardData = null;
3005
+ this.groupExpiryRefreshTriggered = false; // Reset expiry refresh flag for new render
2998
3006
  // Listen for realtime fulfillment updates once per page
2999
3007
  this.subscribeToSocketEvents();
3000
3008
  // Host safety + idempotency markers
@@ -3409,7 +3417,6 @@ class WidgetRoot {
3409
3417
  }
3410
3418
  }
3411
3419
  createWidget(rewardData, container, options) {
3412
- var _a, _b;
3413
3420
  const isFulfilled = this.groupFulfilled;
3414
3421
  const activeReward = this.frozenReward || (rewardData === null || rewardData === void 0 ? void 0 : rewardData.reward) || null;
3415
3422
  const wrapper = document.createElement("div");
@@ -3459,7 +3466,7 @@ class WidgetRoot {
3459
3466
  rewardLine.setAttribute("aria-label", rewardText ? `Reward locked in: ${rewardText}` : "Reward available for this group");
3460
3467
  rewardLine.title = rewardLine.textContent;
3461
3468
  }
3462
- 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) {
3463
3470
  const rewardText = this.formatRewardText(activeReward);
3464
3471
  rewardLine.textContent = rewardText
3465
3472
  ? `Save up to ${rewardText} with CoBuy`
@@ -3467,12 +3474,6 @@ class WidgetRoot {
3467
3474
  rewardLine.setAttribute("aria-label", `Eligible for CoBuy reward: ${rewardLine.textContent}`);
3468
3475
  rewardLine.title = rewardLine.textContent;
3469
3476
  }
3470
- else if (rewardData && !((_b = rewardData.eligibility) === null || _b === void 0 ? void 0 : _b.isEligible)) {
3471
- rewardLine.textContent = "Join with CoBuy to unlock rewards";
3472
- rewardLine.setAttribute("aria-label", "Join with CoBuy to unlock rewards");
3473
- rewardLine.title = "Join with CoBuy to unlock rewards";
3474
- rewardLine.style.color = "#6b7280";
3475
- }
3476
3477
  else {
3477
3478
  rewardLine.textContent = "CoBuy offer loading or unavailable";
3478
3479
  rewardLine.setAttribute("aria-label", "CoBuy offer loading or unavailable");
@@ -3876,7 +3877,6 @@ class WidgetRoot {
3876
3877
  * Format reward text for rendering in external container
3877
3878
  */
3878
3879
  formatRewardForContainer(rewardData) {
3879
- var _a;
3880
3880
  const reward = this.frozenReward || (rewardData === null || rewardData === void 0 ? void 0 : rewardData.reward);
3881
3881
  if (this.groupFulfilled) {
3882
3882
  const rewardText = this.formatRewardText(reward);
@@ -3886,12 +3886,7 @@ class WidgetRoot {
3886
3886
  return "Join with CoBuy to unlock rewards";
3887
3887
  }
3888
3888
  const rewardText = this.formatRewardText(reward);
3889
- if ((_a = rewardData === null || rewardData === void 0 ? void 0 : rewardData.eligibility) === null || _a === void 0 ? void 0 : _a.isEligible) {
3890
- return rewardText ? `Save up to ${rewardText} with CoBuy` : "CoBuy reward available";
3891
- }
3892
- else {
3893
- return "Join with CoBuy to unlock rewards";
3894
- }
3889
+ return rewardText ? `Save up to ${rewardText} with CoBuy` : "CoBuy reward available";
3895
3890
  }
3896
3891
  }
3897
3892
 
@@ -3907,6 +3902,9 @@ const API_ENDPOINTS = {
3907
3902
  GROUP_CREATE_AND_JOIN: "/v1/sdk/groups/new/join",
3908
3903
  PRODUCT_ACTIVE_GROUPS: "/v1/sdk/products/:productId/groups/active",
3909
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",
3910
3908
  };
3911
3909
  /**
3912
3910
  * Build full API URL from base URL and endpoint path
@@ -4361,6 +4359,100 @@ class ApiClient {
4361
4359
  },
4362
4360
  };
4363
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
+ }
4364
4456
  }
4365
4457
 
4366
4458
  /**
@@ -8755,6 +8847,7 @@ class CoBuy {
8755
8847
  this.analyticsClient = null;
8756
8848
  this.sessionId = "";
8757
8849
  this.SESSION_STORAGE_KEY = "cobuy_sdk_session_id";
8850
+ this.CHECKOUT_REF_PREFIX = "cobuy_checkout_ref";
8758
8851
  this.lobbyModal = null;
8759
8852
  this.modals = new Map();
8760
8853
  this.socketManager = null;
@@ -8798,12 +8891,97 @@ class CoBuy {
8798
8891
  // Fallback for environments without crypto.randomUUID
8799
8892
  return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
8800
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
+ }
8801
8945
  /**
8802
8946
  * Get the current session ID (core SDK concept)
8803
8947
  */
8804
8948
  getSessionId() {
8805
8949
  return this.sessionId;
8806
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
+ }
8807
8985
  /**
8808
8986
  * Initialize the SDK with configuration
8809
8987
  */
@@ -8864,6 +9042,21 @@ class CoBuy {
8864
9042
  },
8865
9043
  onGroupMemberJoined: (payload) => {
8866
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
8867
9060
  if ((_a = config.events) === null || _a === void 0 ? void 0 : _a.onGroupMemberJoined) {
8868
9061
  config.events.onGroupMemberJoined(payload);
8869
9062
  }
@@ -8972,6 +9165,17 @@ class CoBuy {
8972
9165
  this.lobbyModal = modal;
8973
9166
  // Open the modal
8974
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
+ }
8975
9179
  // Call callback if provided
8976
9180
  if (options.onOpen) {
8977
9181
  options.onOpen(options.productId);
@@ -9053,6 +9257,83 @@ class CoBuy {
9053
9257
  this.logger.error("Error setting contact information", error);
9054
9258
  }
9055
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
+ }
9056
9337
  /**
9057
9338
  * Get the initialized API client instance
9058
9339
  */