@cshah18/sdk 3.0.4 → 4.0.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.
@@ -304,11 +304,44 @@ class GroupListModal {
304
304
  this.currentSessionId = null;
305
305
  this.onGroupJoined = null;
306
306
  this.onViewProgress = null;
307
+ this.socketListenerRegistered = false;
307
308
  this.escapeHandler = (event) => {
308
309
  if (event.key === "Escape") {
309
310
  this.close();
310
311
  }
311
312
  };
313
+ this.handleGroupMemberJoinedEvent = (event) => {
314
+ this.onGroupMemberJoined(event);
315
+ };
316
+ /** Handle group member joined socket event and update groups list */
317
+ this.onGroupMemberJoined = (event) => {
318
+ const detail = event.detail || {};
319
+ const productId = detail.product_id;
320
+ const groupData = detail.group;
321
+ // Only process if this is for the current product
322
+ if (!productId || !this.currentProductId || productId !== this.currentProductId) {
323
+ return;
324
+ }
325
+ if (!groupData) {
326
+ return;
327
+ }
328
+ const groupId = groupData.id;
329
+ const participantsCount = groupData.participants_count;
330
+ if (!groupId) {
331
+ return;
332
+ }
333
+ // Find and update the group in the list
334
+ const groupIndex = this.groups.findIndex((g) => g.groupId === groupId);
335
+ if (groupIndex !== -1) {
336
+ // Update the joined count
337
+ if (typeof participantsCount === "number") {
338
+ this.groups[groupIndex].joined = participantsCount;
339
+ }
340
+ this.logger.info(`[GroupListModal] Updated group ${groupId} - participants: ${participantsCount}`);
341
+ // Re-render the specific group card
342
+ this.updateGroupCard(groupId);
343
+ }
344
+ };
312
345
  this.logger = new Logger(debug);
313
346
  this.groups = groups;
314
347
  this.liveCount = liveCount;
@@ -335,6 +368,65 @@ class GroupListModal {
335
368
  hasGroup(groupId) {
336
369
  return this.groups.some((group) => group.groupId === groupId);
337
370
  }
371
+ /** Subscribe to socket events for real-time group updates */
372
+ subscribeToSocketEvents() {
373
+ if (typeof window === "undefined" || this.socketListenerRegistered) {
374
+ return;
375
+ }
376
+ window.addEventListener("group:member:joined", this.handleGroupMemberJoinedEvent);
377
+ this.socketListenerRegistered = true;
378
+ this.logger.debug("[GroupListModal] Socket event listeners registered");
379
+ }
380
+ /** Unsubscribe from socket events */
381
+ unsubscribeFromSocketEvents() {
382
+ if (typeof window === "undefined" || !this.socketListenerRegistered) {
383
+ return;
384
+ }
385
+ window.removeEventListener("group:member:joined", this.handleGroupMemberJoinedEvent);
386
+ this.socketListenerRegistered = false;
387
+ this.logger.debug("[GroupListModal] Socket event listeners unregistered");
388
+ }
389
+ /** Update the rendered group card with new data */
390
+ updateGroupCard(groupId) {
391
+ if (!this.overlayEl) {
392
+ return;
393
+ }
394
+ const groupCard = this.overlayEl.querySelector(`[data-group-id="${groupId}"]`);
395
+ if (!groupCard) {
396
+ return;
397
+ }
398
+ const group = this.groups.find((g) => g.groupId === groupId);
399
+ if (!group) {
400
+ return;
401
+ }
402
+ // Update the progress info
403
+ const remaining = Math.max(group.total - group.joined, 0);
404
+ const joinedCountEl = groupCard.querySelector(".cobuy-joined-count");
405
+ const spotsLeftEl = groupCard.querySelector(".cobuy-spots-left");
406
+ if (joinedCountEl) {
407
+ joinedCountEl.textContent = `${group.joined} Joined`;
408
+ }
409
+ if (spotsLeftEl) {
410
+ spotsLeftEl.textContent = `${remaining} ${remaining === 1 ? "spot" : "spots"} left`;
411
+ }
412
+ // Update the progress bar
413
+ const progressFill = groupCard.querySelector(".cobuy-gl-progress-fill");
414
+ if (progressFill) {
415
+ const pct = Math.max(0, Math.min(100, Math.round((group.joined / group.total) * 100)));
416
+ progressFill.style.width = `${pct}%`;
417
+ }
418
+ // Update member avatars
419
+ const membersContainer = groupCard.querySelector(".cobuy-group-members");
420
+ if (membersContainer) {
421
+ // Clear existing avatars
422
+ membersContainer.innerHTML = "";
423
+ // Recreate avatars with updated joined count
424
+ for (let i = 0; i < group.total; i++) {
425
+ const avatar = this.createMemberAvatar(i >= group.joined);
426
+ membersContainer.appendChild(avatar);
427
+ }
428
+ }
429
+ }
338
430
  async open(productId, sessionId, joinedGroupId) {
339
431
  if (this.overlayEl) {
340
432
  this.logger.debug("Group list modal already open");
@@ -380,6 +472,8 @@ class GroupListModal {
380
472
  this.overlayEl = overlay;
381
473
  document.body.appendChild(overlay);
382
474
  document.addEventListener("keydown", this.escapeHandler);
475
+ // Subscribe to socket events for real-time group updates
476
+ this.subscribeToSocketEvents();
383
477
  requestAnimationFrame(() => {
384
478
  overlay.classList.add("cobuy-gl-open");
385
479
  });
@@ -477,6 +571,8 @@ class GroupListModal {
477
571
  if (!this.overlayEl) {
478
572
  return;
479
573
  }
574
+ // Unsubscribe from socket events
575
+ this.unsubscribeFromSocketEvents();
480
576
  // Clear any running countdown intervals to avoid leaks
481
577
  this.countdownIntervals.forEach((id) => window.clearInterval(id));
482
578
  this.countdownIntervals = [];
@@ -720,6 +816,7 @@ class GroupListModal {
720
816
  createGroupCard(group) {
721
817
  const card = document.createElement("div");
722
818
  card.className = "cobuy-group-card";
819
+ card.setAttribute("data-group-id", group.groupId);
723
820
  const header = document.createElement("div");
724
821
  header.className = "cobuy-group-card-header";
725
822
  const groupId = document.createElement("div");
@@ -2633,7 +2730,6 @@ class WidgetRoot {
2633
2730
  }
2634
2731
  /** Fetch latest group data and re-render containers */
2635
2732
  async refreshGroupDataFromRealtime() {
2636
- console.log("request group data realtime callledddd");
2637
2733
  // Debounce rapid refreshes to prevent loops and reduce API load
2638
2734
  const now = Date.now();
2639
2735
  if (now - this.lastGroupDataRefreshTime < this.GROUP_REFRESH_DEBOUNCE) {
@@ -2658,6 +2754,9 @@ class WidgetRoot {
2658
2754
  this.groupFulfilled = true;
2659
2755
  }
2660
2756
  }
2757
+ else {
2758
+ this.groupFulfilled = false;
2759
+ }
2661
2760
  this.refreshRenderedContainers();
2662
2761
  }
2663
2762
  catch (error) {
@@ -3048,7 +3147,6 @@ class WidgetRoot {
3048
3147
  let groupData = null;
3049
3148
  if (this.apiClient) {
3050
3149
  rewardData = await this.fetchRewardWithRetry(options.productId);
3051
- console.log("from renderrrr");
3052
3150
  groupData = await this.fetchPrimaryGroup(options.productId);
3053
3151
  this.currentGroupData = groupData;
3054
3152
  this.currentGroupId = (groupData === null || groupData === void 0 ? void 0 : groupData.id) || null;
@@ -3305,7 +3403,6 @@ class WidgetRoot {
3305
3403
  */
3306
3404
  async fetchPrimaryGroup(productId) {
3307
3405
  var _a;
3308
- console.log("fetch primary group called");
3309
3406
  if (!this.apiClient) {
3310
3407
  return null;
3311
3408
  }
@@ -3422,6 +3519,7 @@ class WidgetRoot {
3422
3519
  createWidget(rewardData, container, options) {
3423
3520
  const isFulfilled = this.groupFulfilled;
3424
3521
  const activeReward = this.frozenReward || (rewardData === null || rewardData === void 0 ? void 0 : rewardData.reward) || null;
3522
+ this.logger.info(`activeReward: ${JSON.stringify(activeReward)}`);
3425
3523
  const wrapper = document.createElement("div");
3426
3524
  wrapper.className = "cobuy-widget";
3427
3525
  wrapper.style.display = "grid";
@@ -3461,28 +3559,31 @@ class WidgetRoot {
3461
3559
  rewardLine.style.opacity = "0";
3462
3560
  rewardLine.style.animation =
3463
3561
  "cobuy-fadeIn var(--cobuy-animation-duration, 300ms) var(--cobuy-animation-easing, ease-out) forwards";
3464
- if (isFulfilled) {
3465
- const rewardText = this.formatRewardText(activeReward);
3466
- rewardLine.textContent = rewardText
3467
- ? `Reward available: ${rewardText}`
3468
- : "Reward available for this group";
3469
- rewardLine.setAttribute("aria-label", rewardText ? `Reward locked in: ${rewardText}` : "Reward available for this group");
3470
- rewardLine.title = rewardLine.textContent;
3471
- }
3472
- else if (activeReward) {
3473
- const rewardText = this.formatRewardText(activeReward);
3474
- rewardLine.textContent = rewardText
3475
- ? `Save up to ${rewardText} with CoBuy`
3476
- : "CoBuy reward available";
3477
- rewardLine.setAttribute("aria-label", `Eligible for CoBuy reward: ${rewardLine.textContent}`);
3478
- rewardLine.title = rewardLine.textContent;
3479
- }
3480
- else {
3481
- rewardLine.textContent = "CoBuy offer loading or unavailable";
3482
- rewardLine.setAttribute("aria-label", "CoBuy offer loading or unavailable");
3483
- rewardLine.title = "CoBuy offer loading or unavailable";
3484
- rewardLine.style.color = "#6b7280";
3485
- }
3562
+ // if (isFulfilled) {
3563
+ // const rewardText = this.formatRewardText(activeReward);
3564
+ // rewardLine.textContent = rewardText
3565
+ // ? `Reward available: ${rewardText}`
3566
+ // : "Reward available for this group";
3567
+ // rewardLine.setAttribute(
3568
+ // "aria-label",
3569
+ // rewardText ? `Reward locked in: ${rewardText}` : "Reward available for this group",
3570
+ // );
3571
+ // rewardLine.title = rewardLine.textContent;
3572
+ // }
3573
+ // else if (activeReward) {
3574
+ // const rewardText = this.formatRewardText(activeReward);
3575
+ // rewardLine.textContent = rewardText
3576
+ // ? `Save up to ${rewardText} with CoBuy`
3577
+ // : "CoBuy reward available";
3578
+ // rewardLine.setAttribute("aria-label", `Eligible for CoBuy reward: ${rewardLine.textContent}`);
3579
+ // rewardLine.title = rewardLine.textContent;
3580
+ // }
3581
+ // else {
3582
+ // rewardLine.textContent = "CoBuy offer loading or unavailable";
3583
+ // rewardLine.setAttribute("aria-label", "CoBuy offer loading or unavailable");
3584
+ // rewardLine.title = "CoBuy offer loading or unavailable";
3585
+ // rewardLine.style.color = "#6b7280";
3586
+ // }
3486
3587
  sections.reward = rewardLine;
3487
3588
  // Button - semantic button element with accessibility
3488
3589
  const button = document.createElement("button");
@@ -8951,9 +9052,7 @@ class CoBuy {
8951
9052
  const ref = window.localStorage.getItem(key);
8952
9053
  if (ref) {
8953
9054
  this.logger.debug(`[SDK] Retrieved checkout reference via prefix: ${key}`);
8954
- const parsedGroupId = key.startsWith(`${basePrefix}_`)
8955
- ? key.substring(basePrefix.length + 1)
8956
- : null;
9055
+ const parsedGroupId = key.startsWith(`${basePrefix}_`) ? key.substring(basePrefix.length + 1) : null;
8957
9056
  return { key, checkoutRef: ref, groupId: parsedGroupId };
8958
9057
  }
8959
9058
  }
@@ -9374,7 +9473,6 @@ class CoBuy {
9374
9473
  const pid = typeof w.getProductId === "function" ? w.getProductId() : null;
9375
9474
  if (!productId || pid === productId) {
9376
9475
  if (typeof w.requestRefresh === "function") {
9377
- console.log("calling refresshh now");
9378
9476
  refreshPromises.push(w.requestRefresh());
9379
9477
  }
9380
9478
  }