@cshah18/sdk 4.15.0 → 4.16.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.
@@ -2294,6 +2294,11 @@ var CoBuySDK = (function (exports) {
2294
2294
  this.updateData(updatePayload);
2295
2295
  // Also update team card to reflect new member count
2296
2296
  this.updateTeamCard(participants, max);
2297
+ // If group just became complete and we need offline codes for THIS user, fetch them
2298
+ if (isComplete && !this.data.offlineRedemption) {
2299
+ this.logger.info("[Socket] Group fulfilled - fetching current user's offline codes");
2300
+ this.fetchCurrentUserOfflineCodesIfNeeded();
2301
+ }
2297
2302
  };
2298
2303
  this.logger = new Logger(debug);
2299
2304
  this.apiClient = apiClient;
@@ -4537,6 +4542,33 @@ var CoBuySDK = (function (exports) {
4537
4542
  window.removeEventListener("group:created", this.handleSocketGroupUpdate);
4538
4543
  this.socketListenerRegistered = false;
4539
4544
  }
4545
+ /**
4546
+ * Fetch current user's offline redemption codes when group becomes fulfilled
4547
+ * This ensures we show the current user's codes, not someone else's
4548
+ */
4549
+ async fetchCurrentUserOfflineCodesIfNeeded() {
4550
+ var _a;
4551
+ if (!this.apiClient || !this.currentGroupId) {
4552
+ return;
4553
+ }
4554
+ try {
4555
+ this.logger.info("[Offline] Fetching current user's offline codes");
4556
+ const response = await this.apiClient.getGroupOfflineRedemption(this.currentGroupId);
4557
+ if (response.success && ((_a = response.data) === null || _a === void 0 ? void 0 : _a.offline_redemption)) {
4558
+ const offlineRedemption = response.data.offline_redemption;
4559
+ if (isValidOfflineRedemption(offlineRedemption)) {
4560
+ this.logger.info("[Offline] Successfully fetched current user's offline codes");
4561
+ this.updateData({ offlineRedemption });
4562
+ }
4563
+ }
4564
+ else {
4565
+ this.logger.warn("[Offline] Failed to fetch offline codes", response.error);
4566
+ }
4567
+ }
4568
+ catch (error) {
4569
+ this.logger.error("[Offline] Error fetching offline codes", error);
4570
+ }
4571
+ }
4540
4572
  /**
4541
4573
  * Create activity item from socket event data
4542
4574
  */
@@ -5218,6 +5250,7 @@ var CoBuySDK = (function (exports) {
5218
5250
  }
5219
5251
  /** Fetch latest group data and re-render containers */
5220
5252
  async refreshGroupDataFromRealtime() {
5253
+ var _a;
5221
5254
  // Debounce rapid refreshes to prevent loops and reduce API load
5222
5255
  const now = Date.now();
5223
5256
  if (now - this.lastGroupDataRefreshTime < this.GROUP_REFRESH_DEBOUNCE) {
@@ -5234,19 +5267,24 @@ var CoBuySDK = (function (exports) {
5234
5267
  const groupData = await this.fetchPrimaryGroup(this.currentProductId);
5235
5268
  this.currentGroupData = groupData;
5236
5269
  this.currentGroupId = (groupData === null || groupData === void 0 ? void 0 : groupData.id) || this.currentGroupId;
5270
+ // If backend returned member-scoped offline redemption, this session is a member.
5271
+ const hasMemberOfflineRedemption = !!(groupData === null || groupData === void 0 ? void 0 : groupData.offline_redemption) && isValidOfflineRedemption(groupData.offline_redemption);
5272
+ if (hasMemberOfflineRedemption && !this.currentSessionId) {
5273
+ this.currentSessionId = ((_a = this.apiClient) === null || _a === void 0 ? void 0 : _a.getSessionId()) || null;
5274
+ }
5237
5275
  // If backend signals completion via counts, reflect it — but only for actual members.
5238
5276
  // Observers may see a full group returned by fetchPrimaryGroup; they should NOT enter
5239
5277
  // the checkout flow. currentSessionId is the membership signal (non-null = joined).
5240
5278
  if (groupData) {
5241
5279
  const participants = Number(groupData.participants_count || 0);
5242
5280
  const max = Number(groupData.max_participants || 0);
5243
- if (max > 0 && participants >= max && this.currentSessionId) {
5281
+ const isMember = !!this.currentSessionId || hasMemberOfflineRedemption;
5282
+ if (max > 0 && participants >= max && isMember) {
5244
5283
  this.groupFulfilled = true;
5245
5284
  // The primary group API returns offline_redemption for members of fulfilled groups.
5246
5285
  // Extract it here so renderFulfilledSummary shows the "Redeem In-store" link
5247
5286
  // (matching the UI users see on a full page reload).
5248
- if (groupData.offline_redemption &&
5249
- isValidOfflineRedemption(groupData.offline_redemption)) {
5287
+ if (hasMemberOfflineRedemption) {
5250
5288
  this.offlineRedemption = groupData.offline_redemption;
5251
5289
  }
5252
5290
  if (groupData.campaign_redemption_method) {
@@ -6649,7 +6687,7 @@ var CoBuySDK = (function (exports) {
6649
6687
  * Handle CTA button click with analytics and modal opening
6650
6688
  */
6651
6689
  async handleCTAClick(productId) {
6652
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
6690
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
6653
6691
  this.logger.info(`CTA clicked for product: ${productId}`);
6654
6692
  // Track analytics event asynchronously (fire-and-forget)
6655
6693
  if (this.analyticsClient) {
@@ -6769,6 +6807,8 @@ var CoBuySDK = (function (exports) {
6769
6807
  }
6770
6808
  }
6771
6809
  this.logger.info("Successfully joined group", groupJoinData);
6810
+ // Mark this widget session as an active member for subsequent socket fulfillment handling.
6811
+ this.currentSessionId = ((_j = this.apiClient) === null || _j === void 0 ? void 0 : _j.getSessionId()) || this.currentSessionId;
6772
6812
  if (this.analyticsClient && groupJoinData) {
6773
6813
  this.analyticsClient
6774
6814
  .trackJoinSuccess(productId, groupJoinData.group.id)
@@ -6780,7 +6820,7 @@ var CoBuySDK = (function (exports) {
6780
6820
  isValidOfflineRedemption(groupJoinData.offline_redemption)
6781
6821
  ? groupJoinData.offline_redemption
6782
6822
  : null;
6783
- const joinedGroupId = (_j = groupJoinData === null || groupJoinData === void 0 ? void 0 : groupJoinData.group) === null || _j === void 0 ? void 0 : _j.id;
6823
+ const joinedGroupId = (_k = groupJoinData === null || groupJoinData === void 0 ? void 0 : groupJoinData.group) === null || _k === void 0 ? void 0 : _k.id;
6784
6824
  // Trigger invite tracking before opening lobby (global for product)
6785
6825
  if (joinedGroupId) {
6786
6826
  try {
@@ -6812,7 +6852,7 @@ var CoBuySDK = (function (exports) {
6812
6852
  }
6813
6853
  if (this.analyticsClient) {
6814
6854
  this.analyticsClient
6815
- .trackJoinFailure(productId, (_k = this.currentGroupId) !== null && _k !== void 0 ? _k : undefined, "EXCEPTION", error instanceof Error ? error.message : String(error))
6855
+ .trackJoinFailure(productId, (_l = this.currentGroupId) !== null && _l !== void 0 ? _l : undefined, "EXCEPTION", error instanceof Error ? error.message : String(error))
6816
6856
  .catch((e) => this.logger.warn("Analytics tracking failed", e));
6817
6857
  }
6818
6858
  this.setButtonLoadingState(false);
@@ -6829,7 +6869,7 @@ var CoBuySDK = (function (exports) {
6829
6869
  const progress = Math.round((groupJoinData.group.participants_count / groupJoinData.group.max_participants) * 100);
6830
6870
  // Format discount based on reward type
6831
6871
  let discountText = "";
6832
- if ((_m = (_l = this.currentRewardData) === null || _l === void 0 ? void 0 : _l.reward) === null || _m === void 0 ? void 0 : _m.value) {
6872
+ if ((_o = (_m = this.currentRewardData) === null || _m === void 0 ? void 0 : _m.reward) === null || _o === void 0 ? void 0 : _o.value) {
6833
6873
  const rewardType = this.currentRewardData.reward.type;
6834
6874
  const rewardValue = this.currentRewardData.reward.value;
6835
6875
  if (rewardType === "percentage" || rewardType === "cashback") {
@@ -6869,7 +6909,7 @@ var CoBuySDK = (function (exports) {
6869
6909
  shareMessage: shareMessageFromInvite,
6870
6910
  isLocked: !isGroupFulfilled,
6871
6911
  offlineRedemption: offlineRedemptionFromJoin,
6872
- redemptionMethod: (_o = groupJoinData.group.campaign_redemption_method) !== null && _o !== void 0 ? _o : this.campaignRedemptionMethod,
6912
+ redemptionMethod: (_p = groupJoinData.group.campaign_redemption_method) !== null && _p !== void 0 ? _p : this.campaignRedemptionMethod,
6873
6913
  onShare: this.analyticsClient
6874
6914
  ? () => {
6875
6915
  this.analyticsClient.trackShareClick(productId, groupJoinData.group.id, "other").catch((e) => this.logger.warn("Analytics tracking failed", e));
@@ -7047,6 +7087,7 @@ var CoBuySDK = (function (exports) {
7047
7087
  GROUP_CREATE_AND_JOIN: "/v1/sdk/groups/new/join",
7048
7088
  PRODUCT_ACTIVE_GROUPS: "/v1/sdk/products/:productId/groups/active",
7049
7089
  GROUP_INVITE: "/v1/sdk/groups/:groupId/invite",
7090
+ GROUP_OFFLINE_REDEMPTION: "/v1/sdk/groups/:groupId/offline-redemption",
7050
7091
  GROUP_CHECKOUT_PREPARE: "/v1/sdk/groups/:groupId/checkout/prepare",
7051
7092
  GROUP_CHECKOUT_VALIDATE: "/v1/sdk/groups/:groupId/checkout/validate",
7052
7093
  GROUP_CHECKOUT_CONFIRM: "/v1/sdk/groups/:groupId/checkout/confirm",
@@ -8159,6 +8200,29 @@ var CoBuySDK = (function (exports) {
8159
8200
  },
8160
8201
  };
8161
8202
  }
8203
+ /**
8204
+ * Fetch current session member's offline redemption codes for a group.
8205
+ */
8206
+ async getGroupOfflineRedemption(groupId) {
8207
+ const endpoint = buildApiUrl("", API_ENDPOINTS.GROUP_OFFLINE_REDEMPTION, {
8208
+ groupId,
8209
+ });
8210
+ const response = await this.get(endpoint);
8211
+ if (response.success) {
8212
+ const payload = response.data;
8213
+ return {
8214
+ success: true,
8215
+ data: (payload === null || payload === void 0 ? void 0 : payload.data) || {},
8216
+ };
8217
+ }
8218
+ return {
8219
+ success: false,
8220
+ error: response.error || {
8221
+ message: "Failed to fetch offline redemption",
8222
+ code: "OFFLINE_REDEMPTION_FETCH_ERROR",
8223
+ },
8224
+ };
8225
+ }
8162
8226
  async recoverOrJoinGroup(productId, contact) {
8163
8227
  var _a;
8164
8228
  const endpoint = buildApiUrl("", API_ENDPOINTS.PRODUCT_RECOVER_OR_JOIN_GROUP, {
@@ -14438,6 +14502,18 @@ var CoBuySDK = (function (exports) {
14438
14502
  if ((_a = config.events) === null || _a === void 0 ? void 0 : _a.onModalClose) {
14439
14503
  config.events.onModalClose(options.productId);
14440
14504
  }
14505
+ // Sync widget state after lobby closes so fulfilled CTAs/group view
14506
+ // reflect socket-driven changes without requiring a page reload.
14507
+ const refreshPromises = [];
14508
+ this.widgets.forEach((w) => {
14509
+ const pid = typeof w.getProductId === "function"
14510
+ ? w.getProductId()
14511
+ : null;
14512
+ if (pid === options.productId && typeof w.requestRefresh === "function") {
14513
+ refreshPromises.push(w.requestRefresh());
14514
+ }
14515
+ });
14516
+ void Promise.all(refreshPromises.map((p) => p.then(() => undefined).catch(() => undefined)));
14441
14517
  },
14442
14518
  onCopyLink: options.onCopyLink,
14443
14519
  onShare: options.onShare,