@cshah18/sdk 4.14.0 → 4.15.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.
@@ -840,6 +840,7 @@ var CoBuySDK = (function (exports) {
840
840
  this.onGroupMemberJoined = (event) => {
841
841
  const detail = event.detail || {};
842
842
  console.log("eventttttt", detail);
843
+ const eventType = event.type;
843
844
  const productId = detail.product_id;
844
845
  const groupData = detail.group;
845
846
  // Only process if this is for the current product
@@ -861,6 +862,16 @@ var CoBuySDK = (function (exports) {
861
862
  if (typeof participantsCount === "number") {
862
863
  this.groups[groupIndex].joined = participantsCount;
863
864
  }
865
+ // If this session left the currently joined group, clear stale local membership state.
866
+ const leavingSessionId = detail.session_id;
867
+ if (eventType === "group:member:left" &&
868
+ this.currentSessionId &&
869
+ leavingSessionId === this.currentSessionId &&
870
+ this.currentJoinedGroupId === groupId) {
871
+ this.currentJoinedGroupId = null;
872
+ this.groups[groupIndex].isMember = false;
873
+ this.updateStartButtonState(false, this.isLoading);
874
+ }
864
875
  this.logger.info(`[GroupListModal] Updated group ${groupId} - participants: ${participantsCount}`);
865
876
  // Re-render the specific group card
866
877
  this.updateGroupCard(groupId);
@@ -902,6 +913,7 @@ var CoBuySDK = (function (exports) {
902
913
  return;
903
914
  }
904
915
  window.addEventListener("group:member:joined", this.handleGroupMemberJoinedEvent);
916
+ window.addEventListener("group:member:left", this.handleGroupMemberJoinedEvent);
905
917
  this.socketListenerRegistered = true;
906
918
  this.logger.debug("[GroupListModal] Socket event listeners registered");
907
919
  }
@@ -911,6 +923,7 @@ var CoBuySDK = (function (exports) {
911
923
  return;
912
924
  }
913
925
  window.removeEventListener("group:member:joined", this.handleGroupMemberJoinedEvent);
926
+ window.removeEventListener("group:member:left", this.handleGroupMemberJoinedEvent);
914
927
  this.socketListenerRegistered = false;
915
928
  this.logger.debug("[GroupListModal] Socket event listeners unregistered");
916
929
  }
@@ -1042,13 +1055,11 @@ var CoBuySDK = (function (exports) {
1042
1055
  console.log("groupsss", groups);
1043
1056
  // If API reports membership, prefer it over cached state
1044
1057
  const memberGroup = groups.find((g) => g.isMember);
1045
- if (memberGroup) {
1046
- this.currentJoinedGroupId = memberGroup.groupId;
1047
- }
1058
+ this.currentJoinedGroupId = memberGroup ? memberGroup.groupId : null;
1048
1059
  this.groups = groups;
1049
1060
  this.liveCount = groups.length;
1050
1061
  this.logger.info(`Fetched ${groups.length} active groups`);
1051
- const hasMembership = Boolean(this.currentJoinedGroupId || groups.some((g) => g.isMember));
1062
+ const hasMembership = Boolean(memberGroup);
1052
1063
  this.updateStartButtonState(hasMembership, false);
1053
1064
  // Update and show live count display
1054
1065
  const liveCountText = document.getElementById("cobuy-live-count-text");
@@ -1406,7 +1417,7 @@ var CoBuySDK = (function (exports) {
1406
1417
  createGroupCard(group) {
1407
1418
  const card = document.createElement("div");
1408
1419
  card.className = "cobuy-group-card";
1409
- card.dataset.groupId = group.name || group.groupId;
1420
+ card.dataset.groupId = group.groupId;
1410
1421
  const header = document.createElement("div");
1411
1422
  header.className = "cobuy-group-card-header";
1412
1423
  const groupId = document.createElement("div");
@@ -2159,15 +2170,24 @@ var CoBuySDK = (function (exports) {
2159
2170
  }
2160
2171
  }
2161
2172
 
2162
- var css_248z = ".sr-only{clip:rect(0,0,0,0);border-width:0;height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;white-space:nowrap;width:1px}.cb-lobby-modal-container{height:100%;left:0;overflow-y:auto!important;position:fixed;top:0;width:100%;z-index:10000}.cb-lobby-modal-container *{box-sizing:border-box;margin:0;padding:0}.cb-lobby-modal-container body,.cb-lobby-modal-container html{font-family:Inter,sans-serif;height:100%;overflow-x:hidden;width:100%}.cb-lobby-main{backdrop-filter:blur(4px);background-color:color-mix(in oklab,#fff 5%,transparent);border-radius:50px;box-shadow:0 25px 50px -12px #00000040;padding:80px;position:relative;width:100%;z-index:1}.cb-lobby-bg{background-image:url(https://cobuy-dev.s3.af-south-1.amazonaws.com/public/sdk/cb-back-image.png);background-position:50%;background-repeat:no-repeat;background-size:cover;height:100vh;left:0;position:fixed;top:0;width:100vw;z-index:-1}.cb-lobby-main-wp{align-items:center;display:flex;justify-content:center;padding:40px 80px}.lobby-indicator{align-items:center;backdrop-filter:blur(8px);background:rgba(16,185,129,.1);border:1px solid rgba(16,185,129,.3);border-radius:24px;display:flex;gap:12px;margin-bottom:16px;padding:6px 12px;width:fit-content}.lobby-indicator-logo{display:block;flex-shrink:0;height:34px;width:auto}.pulsing-dot{align-items:center;display:flex;height:8px;justify-content:center;position:relative;width:8px}.pulsing-dot:after{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.pulsing-dot:after,.pulsing-dot:before{background:#10b981;border-radius:50%;content:\"\";height:100%;position:absolute;width:100%}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}.indicator-text{color:#047857;font-size:11px;font-weight:800;letter-spacing:.5px;line-height:1;text-transform:uppercase}.lobby-status-section{display:flex;flex-direction:column;margin-bottom:24px}.lobby-status{background:#fff;border-radius:4px;color:#000;font-size:10px;font-weight:600;line-height:1.2;padding:6px 10px;text-transform:uppercase}.lobby-status.active{background:#155dfc;color:#fff}.lobby-status.complete{background:#10b981;color:#fff}.lobby-status-wp{align-items:center;display:flex;flex-wrap:wrap;gap:10px}.lobby-number{backdrop-filter:blur(3px);background:hsla(0,0%,100%,.2);border-radius:4px;box-shadow:0 25px 50px -12px #00000040;font-size:12px;font-weight:700;letter-spacing:1px;line-height:1.2;padding:5px 8px;text-transform:uppercase}.title-wp{margin-top:25px}.title-wp h2{font-size:60px;font-weight:900;line-height:1;margin-bottom:15px}.sub-title{-webkit-text-fill-color:transparent;animation:gradient-flow 4s linear infinite;background-clip:text;-webkit-background-clip:text;background-image:linear-gradient(90deg,#1e293b,#2563eb 25%,#1e293b 50%);background-size:200% auto;color:#1e293b;font-size:16px;font-weight:700;line-height:1.5;margin-bottom:0}@keyframes gradient-flow{0%{background-position:200% 0}to{background-position:-200% 0}}.sub-title.completed{-webkit-text-fill-color:unset;background-clip:unset;-webkit-background-clip:unset;background-image:none;color:#1e293b}.connected-section{backdrop-filter:blur(4px);background:hsla(0,0%,100%,.05);border:1px solid hsla(0,0%,100%,.1);border-radius:24px;box-shadow:0 1px 2px 0 rgba(0,0,0,.05);display:flex;flex-direction:column;gap:20px;margin-top:24px;padding:24px;transition:all .3s ease}.connected-section:hover{background:hsla(0,0%,100%,.1);box-shadow:0 2px 4px 0 rgba(0,0,0,.08)}.link-share-container{display:flex;flex-direction:column}.link-share-wrapper{align-items:center;display:flex;gap:12px;width:100%}.lobby-link-box{align-items:center;backdrop-filter:blur(8px);background-color:hsla(0,0%,100%,.4);border:1px solid hsla(0,0%,100%,.3);border-radius:14px;box-shadow:0 1px 2px 0 rgba(0,0,0,.05);display:flex;flex:1;gap:16px;justify-content:space-between;min-height:50px;padding:16px 20px;transition:all .2s ease}.lobby-link-box:hover{background-color:hsla(0,0%,100%,.5);box-shadow:0 2px 4px 0 rgba(0,0,0,.08)}.lobby-link-text{color:#71717a;font-size:10px;font-weight:700;letter-spacing:.6px;line-height:1.2;margin-bottom:6px;text-transform:uppercase}.copy-link-btn{align-items:center;background:transparent;border:none;border-radius:6px;color:#64748b;cursor:pointer;display:flex;flex-shrink:0;font-size:13px;font-weight:600;gap:6px;justify-content:center;padding:0;transition:all .2s ease;white-space:nowrap}.copy-link-btn:hover{color:#1e293b}.copy-link-btn .copy-text{display:none}.copy-link-btn svg{flex-shrink:0;height:18px;width:18px}@media (min-width:640px){.copy-link-btn .copy-text{display:inline}}.lobby-link-url{color:#1e293b;font-size:15px;font-weight:700;line-height:1.4;word-break:break-all}.link-box-container{flex:1;min-width:0}.share-btn{align-items:center;background:#1e293b;border:none;border-radius:14px;box-shadow:0 2px 4px 0 rgba(0,0,0,.1);color:#fff;cursor:pointer;display:flex;flex-shrink:0;font-size:15px;font-weight:600;gap:8px;height:50px;justify-content:center;min-width:auto;padding:35px 24px;transition:all .2s ease}.share-btn .share-text{color:#fff;display:inline;font-size:18px;margin:0!important}.share-btn svg{color:#fff;flex-shrink:0;height:18px;width:18px}@media (max-width:640px){.share-btn{font-size:14px;height:50px;padding:0 18px}.share-btn .share-text{color:#fff;display:inline}}.share-btn:hover{background:#0f172a;box-shadow:0 4px 8px 0 rgba(0,0,0,.15);transform:translateY(-1px)}.share-btn:active{transform:scale(.95)}.lobby-offer-box{align-items:center;backdrop-filter:blur(8px);background-color:rgba(59,130,246,.063);border:1px solid rgba(59,130,246,.125);border-radius:1rem;display:flex;gap:30px;margin-top:30px;padding:15px 20px}.offer-box-icon{align-items:center;background:linear-gradient(135deg,#3b82f6,rgba(59,130,246,.867));border-radius:10px;box-shadow:0 10px 15px -3px rgba(59,130,246,.314);color:#fff;cursor:pointer;display:flex;height:56px;justify-content:center;padding:5px;width:56px}.offer-lock-status{align-items:center;display:flex;gap:6px;margin-bottom:2px}.offer-lock-status span{font-size:14px;font-weight:700;line-height:1}.offer-box-content h3{font-size:30px;font-weight:900;line-height:1.2}.cb-lobby-top{display:grid;gap:100px;grid-template-columns:7fr 5fr}.group-info{backdrop-filter:blur(8px);background-color:color-mix(in oklab,#fff 5%,transparent);border-radius:20px;box-shadow:0 10px 15px -3px #0000001a;padding:30px}.progress-header{align-items:center;display:flex;justify-content:space-between;margin-bottom:14px}.progress-header .title{align-items:center;color:#000;display:flex;font-size:14px;font-weight:900;justify-content:center;letter-spacing:.7px;position:relative}.progress-badge{background:#3b82f6;border-radius:999px;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a;color:#fff;font-size:13px;font-weight:700;padding:6px 12px}.cb-lobby-modal-container .progress-bar{background:#fff;border-radius:999px;height:14px;overflow:hidden;width:100%}.cb-lobby-modal-container .progress-fill{animation:shimmer 2.7s linear infinite;background:#3b82f6;background-image:linear-gradient(120deg,hsla(0,0%,100%,.15) 25%,hsla(0,0%,100%,.45) 37%,hsla(0,0%,100%,.15) 63%);background-size:200% 100%;border-radius:999px;height:100%;position:relative;transition:width .6s ease;width:0}@keyframes shimmer{0%{background-position:-200% 0}to{background-position:200% 0}}.progress-labels{color:#474d56;display:flex;font-size:12px;justify-content:space-between;margin-top:8px}.team-card{margin-top:40px}.team-card .icon-box svg{width:16px}.team-card .team-header{align-items:center;display:flex;justify-content:space-between}.team-card .team-title{align-items:center;display:flex;font-size:14px;font-weight:600;gap:12px;letter-spacing:1px}.team-card .icon-box{align-items:center;background-color:#3b82f6;border-radius:.5rem;box-shadow:0 10px 15px -3px #3b82f64d;color:#fff;display:flex;font-size:18px;height:2rem;justify-content:center;width:2rem}.team-card .team-title span{color:#000;font-size:14px;font-weight:900;letter-spacing:.7px}.team-card .team-count{background-color:#3b82f6;border-radius:9999px;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a;color:#fff;font-size:13px;font-weight:700;letter-spacing:.7px;padding:6px 12px}.team-card .team-members{align-items:center;display:flex;gap:14px;justify-content:center;margin-top:20px}.team-card .member{border:3px solid #fff;border-radius:50%;box-shadow:0 4px 12px #0000001a;font-size:22px;height:56px;position:relative;width:56px}.team-card .member,.team-card .member:after{align-items:center;color:#fff;display:flex;justify-content:center}.team-card .member:after{background:#3b82f6;background-image:url(https://cobuy-dev.s3.af-south-1.amazonaws.com/public/sdk/tick-mark-icon.svg);background-position:50%;background-repeat:no-repeat;background-size:75%;border:2px solid #fff;border-radius:50%;bottom:-4px;content:\"\";height:12px;padding:2px;position:absolute;right:-4px;width:12px}.team-card .member.blue{background:#2563eb}.team-card .member.purple{background:#9333ea}.team-card .member.pink{background:#ec4899}.team-card .member.orange{background:#f97316}.team-card .member.empty{background:#f8fafc;color:#9ca3af}.team-card .member.empty:after{display:none}.time-card{align-items:center;backdrop-filter:blur(8px);background:hsla(0,0%,100%,.2);border:1px solid hsla(0,0%,100%,.2);border-radius:20px;display:flex;gap:14px;margin-top:30px;padding:15px}.time-card .time-icon{align-items:center;background:#3b82f6;border-radius:14px;color:#fff;display:flex;flex-shrink:0;font-size:22px;height:48px;justify-content:center;width:48px}.time-card .time-content{display:flex;flex-direction:column}.time-card .time-label{color:#4b5563;font-size:12px;font-weight:600;letter-spacing:.6px}.time-card .time-value{color:#111827;font-size:22px;font-weight:900}.group-info-box{backdrop-filter:blur(8px);background:color-mix(in oklab,#fff 5%,transparent);border:1px solid color-mix(in oklab,#fff 20%,transparent);border-radius:1.5rem;box-shadow:0 10px 15px -3px #0000001a;padding:30px}.offer-lock-status svg{height:16px;width:16px}.cb-lobby-modal-container .offer-box-content .reward-text{background:unset;border:none;color:#000;font-size:14px;line-height:1;margin-top:4px}.progress-header .title:before{background:#3b82f6;border-radius:50%;content:\"\";display:inline-block;height:8px;margin-right:8px;position:relative;width:8px}.live-activity-wrapper{backdrop-filter:blur(8px);background-color:color-mix(in oklab,#fff 80%,transparent);border-radius:18px;box-shadow:0 30px 80px rgba(0,0,0,.15);padding:16px}.live-activity-header{display:flex;gap:10px;justify-content:space-between;margin-bottom:12px}.live-activity-header .title{align-items:center;color:#000;display:flex;font-size:14px;font-weight:900;gap:8px;letter-spacing:.7px}.live-activity-header .dot{background:#3b82f6;border-radius:50%;height:8px;position:relative;width:8px}.live-activity-header .dot:after{animation:livePulse 1.6s ease-out infinite;background:rgba(59,130,246,.6);border-radius:50%;content:\"\";inset:0;position:absolute}@keyframes livePulse{0%{opacity:.8;transform:scale(1)}70%{opacity:0;transform:scale(2.4)}to{opacity:0}}.activity-stats{align-items:center;display:flex;gap:8px}.activity-stats-badge{background-color:rgba(59,130,246,.082);border-radius:999px;color:#3b82f6;font-size:12px;font-weight:500;line-height:1;padding:4px 10px}.activity-stats-badge.light{background-color:#f9f3f4;color:#45556c}.activity-list{height:104px;overflow:hidden;position:relative}.activity-card{align-items:center;background:linear-gradient(90deg,#fff,#f2f6ff);border:1px solid #dbeafe;border-radius:14px;display:flex;gap:10px;height:58px;inset:0;padding:12px 10px;position:absolute;transition:transform .6s cubic-bezier(.22,.61,.36,1),opacity .6s}.activity-card .text{font-size:14px}.activity-card .avatar{align-items:center;border-radius:50%;color:#fff;display:flex;flex:0 0 30px;height:30px;justify-content:center;width:30px}.activity-card .pink{background:linear-gradient(135deg,#ec4899,#f472b6)}.activity-card .purple{background:linear-gradient(135deg,#8b5cf6,#a78bfa)}.activity-card .blue{background:linear-gradient(135deg,#3b82f6,#60a5fa)}.activity-card .green{background:linear-gradient(135deg,#10b981,#34d399)}.activity-card .orange{background:linear-gradient(135deg,#f97316,#fb923c)}.activity-card .text p{color:#6b7280;font-size:12px;margin:2px 0 0}.activity-card .time{color:#94a3b8;font-size:10px;margin-left:auto}.lobby-activity-wp{backdrop-filter:blur(12px);background-color:hsla(0,0%,100%,.4);border:1px solid hsla(0,0%,100%,.2);border-radius:25px;box-shadow:0 1px 3px 0 #0000001a;margin-top:50px;padding:8px}.lobby-close-icon{align-items:center;background-color:color-mix(in oklab,#000 80%,transparent);border-radius:50%;color:#fff;cursor:pointer;display:flex;height:34px;justify-content:center;position:fixed;right:30px;top:30px;width:34px;z-index:99}.lobby-close-icon svg{height:20px;width:20px}@media screen and (max-width:1600px){.cb-lobby-main{border-radius:30px;padding:50px}.title-wp h2{font-size:48px;margin-bottom:12px}.sub-title{font-size:16px}.title-wp{margin-top:20px}.lobby-link-section{margin-top:30px}.offer-box-content h3{font-size:26px}.lobby-offer-box{gap:24px;padding:15px}.cb-lobby-top{gap:80px}.group-info-box{border-radius:20px;padding:22px}.team-card{margin-top:30px}.team-card .team-members{margin-top:12px}.lobby-activity-wp{margin-top:40px}.lobby-close-icon{height:30px;top:20px;width:30px}}@media screen and (max-width:1280px){.cb-lobby-main,.cb-lobby-main-wp{padding:40px}.title-wp h2{font-size:42px}.cb-lobby-top{gap:60px}}@media screen and (max-width:1120px){.title-wp h2{font-size:38px}}@media screen and (max-width:991px){.cb-lobby-top{gap:30px;grid-template-columns:1fr}.cb-lobby-main{border-radius:15px;padding:30px}.cb-lobby-main-wp{padding:30px}.lobby-close-icon{right:20px}.lobby-link-box{border-radius:10px}.share-btn{border-radius:8px}.offer-box-content h3{font-size:24px}.lobby-activity-wp,.lobby-offer-box,.time-card{border-radius:15px;margin-top:20px}.live-activity-wrapper{border-radius:10px}.group-info-box{border-radius:15px}}@media screen and (max-width:767px){.link-share-wrapper{flex-direction:column!important}}@media screen and (max-width:575px){.cb-lobby-main,.cb-lobby-main-wp{padding:20px}.title-wp h2{font-size:30px}.lobby-link-text{font-size:11px;margin-bottom:4px}.lobby-link-url{font-size:14px}.lobby-link-box{min-height:48px;padding:12px 16px}.link-share-wrapper{gap:10px}.share-btn{border-radius:8px;font-size:13px;height:48px;min-width:auto;padding:0 14px}.lobby-offer-box{padding:10px}.offer-box-content h3{font-size:20px}.offer-box-content .reward-text{font-size:13px}.group-info-box{padding:13px}.progress-header .title,.team-card .team-title span{font-size:13px}.team-card .member{height:40px;width:40px}.team-card .member:after{height:8px;width:8px}.team-card .team-members{gap:10px;margin-top:12px}.time-card{padding:13px}.team-card{margin-top:22px}.activity-card .text{font-size:12px}.activity-card .text p{font-size:11px}.live-activity-header .title{font-size:12px}.time-card .time-value{font-size:20px}}@media screen and (max-width:480px){.cb-lobby-main-wp{padding:20px 12px}.cb-lobby-main{padding:15px 12px}.lobby-status{font-size:9px}.lobby-number{font-size:10px}.title-wp h2{font-size:28px;margin-bottom:7px}.sub-title{font-size:14px}.lobby-link-section{gap:10px;margin-top:20px}.lobby-offer-box{gap:12px}.offer-box-icon{height:45px;width:45px}.offer-box-content .reward-text,.offer-lock-status span{font-size:12px}.cb-lobby-top{gap:20px}.lobby-close-icon{right:10px;top:10px}.live-activity-header{flex-direction:column;gap:5px}.activity-card{border-radius:9px;padding:6px}}.share-overlay{align-items:center;background:rgba(0,0,0,.45);display:flex;inset:0;justify-content:center;opacity:0;position:fixed;transition:.3s ease;visibility:hidden;z-index:999}.share-overlay.active{opacity:1;visibility:visible}.share-popup{background:#fff;border-radius:18px;max-height:90%;overflow:auto;padding:24px;position:relative;transform:translateY(30px);transition:.35s ease;width:420px}.share-overlay.active .share-popup{transform:translateY(0)}.share-popup .close-btn{align-items:center;background:#f3f4f6;border:none;border-radius:50%;cursor:pointer;display:flex;height:32px;justify-content:center;position:absolute;right:14px;top:14px;transition:.3s;width:32px}.share-popup .close-btn:hover{background:#eeecec}.share-popup h2{font-size:22px;font-weight:600;line-height:1;margin-bottom:10px}.share-popup .subtitle{color:#4a5565;font-size:14px;margin:6px 0 30px}.share-popup .share-grid{display:grid;gap:14px;grid-template-columns:repeat(2,1fr)}.share-popup .share-card{align-items:center;background:#f2f6f9;border-radius:14px;cursor:pointer;display:flex;flex-direction:column;padding:16px;position:relative;text-align:center;transition:.25s ease}.share-popup .share-card:hover{transform:translateY(-3px)}.share-popup .share-card .icon{align-items:center;background:#1877f2;border-radius:50%;color:#fff;display:flex;font-size:30px;height:50px;justify-content:center;margin-bottom:8px;text-align:center;width:50px}.share-popup .share-card span{font-size:13px;font-weight:500}.share-popup .share-card.whatsapp{background:#ecfdf5;border:2px solid #22c55e;color:#22c55e}.share-popup .share-card.whatsapp .icon{background:#22c55e}.share-popup .share-card .badge{background:#2563eb;border-radius:12px;color:#fff;font-size:11px;padding:4px 10px;position:absolute;right:10px;top:-8px}.share-popup .link-box{background:#fbf9fa;border:1px solid #ebe6e7;border-radius:14px;margin-top:18px;padding:14px}.share-popup .link-box label{color:#64748b;font-size:13px}.share-popup .link-row{display:flex;gap:8px;margin-top:6px}.share-popup .link-row input{background:transparent;border:none;color:#334155;flex:1;font-size:13px;letter-spacing:.8px;line-height:1.2;outline:none}.share-popup .link-row button{align-items:center;background:#fff;border:1px solid #ebe6e7;border-radius:10px;cursor:pointer;display:flex;height:35px;justify-content:center;padding:6px 8px;width:35px}.share-popup .success{color:#2563eb;display:block;font-size:12px;margin-top:6px;opacity:0;transition:opacity .3s}.share-popup .success.show{opacity:1}.share-popup .footer-text{color:#64748b;font-size:12px;margin-top:14px;text-align:center}.share-popup .share-card.twitter .icon{background:#000}.share-popup .share-card.facebook .icon{background:#1877f2}.share-popup .share-card.sms .icon{background:#059669}.share-popup .share-card.copied .icon{background:#2563eb}@keyframes entrance-fade-in{0%{opacity:0}to{opacity:1}}@keyframes entrance-scale-in{0%{opacity:0;transform:scale(.9) translateY(20px)}to{opacity:1;transform:scale(1) translateY(0)}}@keyframes entrance-text-fade-in{0%{opacity:0}to{opacity:1}}@keyframes exit-blur-scale{0%{filter:blur(0);opacity:1;transform:scale(1)}to{filter:blur(10px);opacity:0;transform:scale(1.1)}}@keyframes pulse-dot{0%,to{opacity:1}50%{opacity:.5}}.entrance-animation-overlay{align-items:center;animation:entrance-fade-in .8s ease-in-out forwards;background-color:#0f172a;color:#fff;display:flex;flex-direction:column;inset:0;justify-content:center;position:fixed;z-index:9999}.entrance-animation-overlay.exit{animation:exit-blur-scale .8s ease-in-out forwards}.entrance-content{align-items:center;animation:entrance-scale-in .5s ease-out .2s both;display:flex;flex-direction:column}.entrance-icon-box{align-items:center;background:#2563eb;border-radius:16px;box-shadow:0 10px 25px rgba(37,99,235,.2);display:flex;height:64px;justify-content:center;margin-bottom:24px;width:64px}.entrance-icon-box svg{color:#fff;height:32px;width:32px}.entrance-title{font-size:32px;font-weight:700;letter-spacing:-.5px;margin-bottom:12px}@media (min-width:768px){.entrance-title{font-size:48px}}.entrance-message{align-items:center;animation:entrance-text-fade-in .5s ease-out .5s both;color:#60a5fa;display:flex;font-size:18px;font-weight:500;gap:8px}.entrance-pulse-dot{animation:pulse-dot 1.5s ease-in-out infinite;background-color:#60a5fa;border-radius:50%;height:8px;width:8px}";
2173
+ var css_248z = ".sr-only{clip:rect(0,0,0,0);border-width:0;height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;white-space:nowrap;width:1px}.cb-lobby-modal-container{height:100%;left:0;overflow-y:auto!important;position:fixed;top:0;width:100%;z-index:10000}.cb-lobby-modal-container *{box-sizing:border-box;margin:0;padding:0}.cb-lobby-modal-container body,.cb-lobby-modal-container html{font-family:Inter,sans-serif;height:100%;overflow-x:hidden;width:100%}.cb-lobby-main{backdrop-filter:blur(4px);background-color:color-mix(in oklab,#fff 5%,transparent);border-radius:50px;box-shadow:0 25px 50px -12px #00000040;padding:80px;position:relative;width:100%;z-index:1}.cb-lobby-bg{background-image:url(https://cobuy-dev.s3.af-south-1.amazonaws.com/public/sdk/cb-back-image.png);background-position:50%;background-repeat:no-repeat;background-size:cover;height:100vh;left:0;position:fixed;top:0;width:100vw;z-index:-1}.cb-lobby-main-wp{align-items:center;display:flex;justify-content:center;padding:40px 80px}.lobby-indicator{align-items:center;backdrop-filter:blur(8px);background:rgba(16,185,129,.1);border:1px solid rgba(16,185,129,.3);border-radius:24px;display:flex;gap:12px;margin-bottom:16px;padding:6px 12px;width:fit-content}.lobby-indicator-logo{display:block;flex-shrink:0;height:34px;width:auto}.pulsing-dot{align-items:center;display:flex;height:8px;justify-content:center;position:relative;width:8px}.pulsing-dot:after{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.pulsing-dot:after,.pulsing-dot:before{background:#10b981;border-radius:50%;content:\"\";height:100%;position:absolute;width:100%}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}.indicator-text{color:#047857;font-size:11px;font-weight:800;letter-spacing:.5px;line-height:1;text-transform:uppercase}.lobby-status-section{display:flex;flex-direction:column;margin-bottom:24px}.lobby-status{background:#fff;border-radius:4px;color:#000;font-size:10px;font-weight:600;line-height:1.2;padding:6px 10px;text-transform:uppercase}.lobby-status.active{background:#155dfc;color:#fff}.lobby-status.complete{background:#10b981;color:#fff}.lobby-status-wp{align-items:center;display:flex;flex-wrap:wrap;gap:10px}.lobby-number{backdrop-filter:blur(3px);background:hsla(0,0%,100%,.2);border-radius:4px;box-shadow:0 25px 50px -12px #00000040;font-size:12px;font-weight:700;letter-spacing:1px;line-height:1.2;padding:5px 8px;text-transform:uppercase}.title-wp{margin-top:25px}.title-wp h2{font-size:60px;font-weight:900;line-height:1;margin-bottom:15px}.sub-title{-webkit-text-fill-color:transparent;animation:gradient-flow 4s linear infinite;background-clip:text;-webkit-background-clip:text;background-image:linear-gradient(90deg,#1e293b,#2563eb 25%,#1e293b 50%);background-size:200% auto;color:#1e293b;font-size:16px;font-weight:700;line-height:1.5;margin-bottom:0}@keyframes gradient-flow{0%{background-position:200% 0}to{background-position:-200% 0}}.sub-title.completed{-webkit-text-fill-color:unset;background-clip:unset;-webkit-background-clip:unset;background-image:none;color:#1e293b}.connected-section{backdrop-filter:blur(4px);background:hsla(0,0%,100%,.05);border:1px solid hsla(0,0%,100%,.1);border-radius:24px;box-shadow:0 1px 2px 0 rgba(0,0,0,.05);display:flex;flex-direction:column;gap:20px;margin-top:24px;padding:24px;transition:all .3s ease}.connected-section:hover{background:hsla(0,0%,100%,.1);box-shadow:0 2px 4px 0 rgba(0,0,0,.08)}.lobby-contact-protection-banner{align-items:center;background:#fffbeb;border:1px solid #f59e0b;border-radius:12px;display:flex;gap:12px;justify-content:space-between;padding:12px 14px}.lobby-contact-protection-copy{color:#7c2d12;font-size:13px;font-weight:600;line-height:1.4}.lobby-contact-protection-btn{background:#1e293b;border:none;border-radius:8px;color:#fff;cursor:pointer;font-size:12px;font-weight:700;padding:8px 12px;white-space:nowrap}.lobby-contact-protection-btn:hover{background:#0f172a}.lobby-protected-leave-container{align-items:center;background:#f0fdf4;border:1px solid #86efac;border-radius:12px;display:none;gap:12px;justify-content:space-between;padding:12px 14px}.lobby-protected-leave-copy{color:#166534;font-size:13px;font-weight:600;line-height:1.4}.lobby-protected-leave-btn{background:#b91c1c;border:none;border-radius:8px;color:#fff;cursor:pointer;font-size:12px;font-weight:700;padding:8px 12px;white-space:nowrap}.lobby-protected-leave-btn:hover{background:#991b1b}.lobby-contact-overlay{align-items:center;background:rgba(2,6,23,.5);display:flex;inset:0;justify-content:center;padding:20px;position:fixed;z-index:10020}.lobby-contact-card{background:#fff;border-radius:16px;box-shadow:0 12px 32px rgba(15,23,42,.25);display:flex;flex-direction:column;gap:12px;padding:20px;width:min(460px,100%)}.lobby-contact-title{color:#0f172a;font-size:22px;font-weight:800;line-height:1.2}.lobby-contact-subtitle{color:#334155;font-size:14px;line-height:1.5}.lobby-contact-input{border:1px solid #cbd5e1;border-radius:10px;font-size:14px;outline:none;padding:11px 12px;width:100%}.lobby-contact-input:focus{border-color:#1d4ed8;box-shadow:0 0 0 3px rgba(59,130,246,.2)}.lobby-contact-actions{align-items:center;display:flex;flex-wrap:wrap;gap:10px}.lobby-contact-danger,.lobby-contact-primary,.lobby-contact-secondary{border:none;border-radius:10px;cursor:pointer;font-size:13px;font-weight:700;padding:10px 14px}.lobby-contact-danger:disabled,.lobby-contact-primary:disabled,.lobby-contact-secondary:disabled{cursor:not-allowed;opacity:.7}.lobby-contact-primary.is-loading{padding-right:34px;position:relative}.lobby-contact-primary.is-loading:after{animation:lobby-spin .8s linear infinite;border:2px solid hsla(0,0%,100%,.45);border-radius:50%;border-top-color:#fff;content:\"\";height:14px;margin-top:-7px;position:absolute;right:12px;top:50%;width:14px}@keyframes lobby-spin{to{transform:rotate(1turn)}}.lobby-contact-primary{background:#1d4ed8;color:#fff}.lobby-contact-primary:hover{background:#1e40af}.lobby-contact-secondary{background:#e2e8f0;color:#1e293b}.lobby-contact-secondary:hover{background:#cbd5e1}.lobby-contact-danger{background:#fee2e2;color:#991b1b}.lobby-contact-danger:hover{background:#fecaca}.lobby-contact-toast{background:#0f172a;border-radius:10px;bottom:30px;box-shadow:0 8px 20px rgba(0,0,0,.25);color:#fff;font-size:13px;font-weight:600;left:50%;padding:10px 14px;position:fixed;transform:translateX(-50%);z-index:10030}.lobby-blocking-loader-overlay{align-items:center;background:rgba(2,6,23,.45);display:flex;inset:0;justify-content:center;padding:20px;position:fixed;z-index:10035}.lobby-blocking-loader-card{align-items:center;background:#fff;border-radius:12px;box-shadow:0 12px 30px rgba(15,23,42,.24);display:flex;gap:10px;padding:16px 18px}.lobby-blocking-loader-spinner{animation:lobby-spin .8s linear infinite;border:2px solid #cbd5e1;border-radius:50%;border-top-color:#1d4ed8;height:16px;width:16px}.lobby-blocking-loader-text{color:#0f172a;font-size:14px;font-weight:600;margin:0}.link-share-container{display:flex;flex-direction:column}.link-share-wrapper{align-items:center;display:flex;gap:12px;width:100%}.lobby-link-box{align-items:center;backdrop-filter:blur(8px);background-color:hsla(0,0%,100%,.4);border:1px solid hsla(0,0%,100%,.3);border-radius:14px;box-shadow:0 1px 2px 0 rgba(0,0,0,.05);display:flex;flex:1;gap:16px;justify-content:space-between;min-height:50px;padding:16px 20px;transition:all .2s ease}.lobby-link-box:hover{background-color:hsla(0,0%,100%,.5);box-shadow:0 2px 4px 0 rgba(0,0,0,.08)}.lobby-link-text{color:#71717a;font-size:10px;font-weight:700;letter-spacing:.6px;line-height:1.2;margin-bottom:6px;text-transform:uppercase}.copy-link-btn{align-items:center;background:transparent;border:none;border-radius:6px;color:#64748b;cursor:pointer;display:flex;flex-shrink:0;font-size:13px;font-weight:600;gap:6px;justify-content:center;padding:0;transition:all .2s ease;white-space:nowrap}.copy-link-btn:hover{color:#1e293b}.copy-link-btn .copy-text{display:none}.copy-link-btn svg{flex-shrink:0;height:18px;width:18px}@media (min-width:640px){.copy-link-btn .copy-text{display:inline}}@media (max-width:640px){.lobby-contact-protection-banner{align-items:flex-start;flex-direction:column}.lobby-contact-protection-btn{width:100%}.lobby-protected-leave-container{align-items:flex-start;flex-direction:column}.lobby-protected-leave-btn{width:100%}}.lobby-link-url{color:#1e293b;font-size:15px;font-weight:700;line-height:1.4;word-break:break-all}.link-box-container{flex:1;min-width:0}.share-btn{align-items:center;background:#1e293b;border:none;border-radius:14px;box-shadow:0 2px 4px 0 rgba(0,0,0,.1);color:#fff;cursor:pointer;display:flex;flex-shrink:0;font-size:15px;font-weight:600;gap:8px;height:50px;justify-content:center;min-width:auto;padding:35px 24px;transition:all .2s ease}.share-btn .share-text{color:#fff;display:inline;font-size:18px;margin:0!important}.share-btn svg{color:#fff;flex-shrink:0;height:18px;width:18px}@media (max-width:640px){.share-btn{font-size:14px;height:50px;padding:0 18px}.share-btn .share-text{color:#fff;display:inline}}.share-btn:hover{background:#0f172a;box-shadow:0 4px 8px 0 rgba(0,0,0,.15);transform:translateY(-1px)}.share-btn:active{transform:scale(.95)}.lobby-offer-box{align-items:center;backdrop-filter:blur(8px);background-color:rgba(59,130,246,.063);border:1px solid rgba(59,130,246,.125);border-radius:1rem;display:flex;gap:30px;margin-top:30px;padding:15px 20px}.offer-box-icon{align-items:center;background:linear-gradient(135deg,#3b82f6,rgba(59,130,246,.867));border-radius:10px;box-shadow:0 10px 15px -3px rgba(59,130,246,.314);color:#fff;cursor:pointer;display:flex;height:56px;justify-content:center;padding:5px;width:56px}.offer-lock-status{align-items:center;display:flex;gap:6px;margin-bottom:2px}.offer-lock-status span{font-size:14px;font-weight:700;line-height:1}.offer-box-content h3{font-size:30px;font-weight:900;line-height:1.2}.cb-lobby-top{display:grid;gap:100px;grid-template-columns:7fr 5fr}.group-info{backdrop-filter:blur(8px);background-color:color-mix(in oklab,#fff 5%,transparent);border-radius:20px;box-shadow:0 10px 15px -3px #0000001a;padding:30px}.progress-header{align-items:center;display:flex;justify-content:space-between;margin-bottom:14px}.progress-header .title{align-items:center;color:#000;display:flex;font-size:14px;font-weight:900;justify-content:center;letter-spacing:.7px;position:relative}.progress-badge{background:#3b82f6;border-radius:999px;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a;color:#fff;font-size:13px;font-weight:700;padding:6px 12px}.cb-lobby-modal-container .progress-bar{background:#fff;border-radius:999px;height:14px;overflow:hidden;width:100%}.cb-lobby-modal-container .progress-fill{animation:shimmer 2.7s linear infinite;background:#3b82f6;background-image:linear-gradient(120deg,hsla(0,0%,100%,.15) 25%,hsla(0,0%,100%,.45) 37%,hsla(0,0%,100%,.15) 63%);background-size:200% 100%;border-radius:999px;height:100%;position:relative;transition:width .6s ease;width:0}@keyframes shimmer{0%{background-position:-200% 0}to{background-position:200% 0}}.progress-labels{color:#474d56;display:flex;font-size:12px;justify-content:space-between;margin-top:8px}.team-card{margin-top:40px}.team-card .icon-box svg{width:16px}.team-card .team-header{align-items:center;display:flex;justify-content:space-between}.team-card .team-title{align-items:center;display:flex;font-size:14px;font-weight:600;gap:12px;letter-spacing:1px}.team-card .icon-box{align-items:center;background-color:#3b82f6;border-radius:.5rem;box-shadow:0 10px 15px -3px #3b82f64d;color:#fff;display:flex;font-size:18px;height:2rem;justify-content:center;width:2rem}.team-card .team-title span{color:#000;font-size:14px;font-weight:900;letter-spacing:.7px}.team-card .team-count{background-color:#3b82f6;border-radius:9999px;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a;color:#fff;font-size:13px;font-weight:700;letter-spacing:.7px;padding:6px 12px}.team-card .team-members{align-items:center;display:flex;gap:14px;justify-content:center;margin-top:20px}.team-card .member{border:3px solid #fff;border-radius:50%;box-shadow:0 4px 12px #0000001a;font-size:22px;height:56px;position:relative;width:56px}.team-card .member,.team-card .member:after{align-items:center;color:#fff;display:flex;justify-content:center}.team-card .member:after{background:#3b82f6;background-image:url(https://cobuy-dev.s3.af-south-1.amazonaws.com/public/sdk/tick-mark-icon.svg);background-position:50%;background-repeat:no-repeat;background-size:75%;border:2px solid #fff;border-radius:50%;bottom:-4px;content:\"\";height:12px;padding:2px;position:absolute;right:-4px;width:12px}.team-card .member.blue{background:#2563eb}.team-card .member.purple{background:#9333ea}.team-card .member.pink{background:#ec4899}.team-card .member.orange{background:#f97316}.team-card .member.empty{background:#f8fafc;color:#9ca3af}.team-card .member.empty:after{display:none}.time-card{align-items:center;backdrop-filter:blur(8px);background:hsla(0,0%,100%,.2);border:1px solid hsla(0,0%,100%,.2);border-radius:20px;display:flex;gap:14px;margin-top:30px;padding:15px}.time-card .time-icon{align-items:center;background:#3b82f6;border-radius:14px;color:#fff;display:flex;flex-shrink:0;font-size:22px;height:48px;justify-content:center;width:48px}.time-card .time-content{display:flex;flex-direction:column}.time-card .time-label{color:#4b5563;font-size:12px;font-weight:600;letter-spacing:.6px}.time-card .time-value{color:#111827;font-size:22px;font-weight:900}.group-info-box{backdrop-filter:blur(8px);background:color-mix(in oklab,#fff 5%,transparent);border:1px solid color-mix(in oklab,#fff 20%,transparent);border-radius:1.5rem;box-shadow:0 10px 15px -3px #0000001a;padding:30px}.offer-lock-status svg{height:16px;width:16px}.cb-lobby-modal-container .offer-box-content .reward-text{background:unset;border:none;color:#000;font-size:14px;line-height:1;margin-top:4px}.progress-header .title:before{background:#3b82f6;border-radius:50%;content:\"\";display:inline-block;height:8px;margin-right:8px;position:relative;width:8px}.live-activity-wrapper{backdrop-filter:blur(8px);background-color:color-mix(in oklab,#fff 80%,transparent);border-radius:18px;box-shadow:0 30px 80px rgba(0,0,0,.15);padding:16px}.live-activity-header{display:flex;gap:10px;justify-content:space-between;margin-bottom:12px}.live-activity-header .title{align-items:center;color:#000;display:flex;font-size:14px;font-weight:900;gap:8px;letter-spacing:.7px}.live-activity-header .dot{background:#3b82f6;border-radius:50%;height:8px;position:relative;width:8px}.live-activity-header .dot:after{animation:livePulse 1.6s ease-out infinite;background:rgba(59,130,246,.6);border-radius:50%;content:\"\";inset:0;position:absolute}@keyframes livePulse{0%{opacity:.8;transform:scale(1)}70%{opacity:0;transform:scale(2.4)}to{opacity:0}}.activity-stats{align-items:center;display:flex;gap:8px}.activity-stats-badge{background-color:rgba(59,130,246,.082);border-radius:999px;color:#3b82f6;font-size:12px;font-weight:500;line-height:1;padding:4px 10px}.activity-stats-badge.light{background-color:#f9f3f4;color:#45556c}.activity-list{height:104px;overflow:hidden;position:relative}.activity-card{align-items:center;background:linear-gradient(90deg,#fff,#f2f6ff);border:1px solid #dbeafe;border-radius:14px;display:flex;gap:10px;height:58px;inset:0;padding:12px 10px;position:absolute;transition:transform .6s cubic-bezier(.22,.61,.36,1),opacity .6s}.activity-card .text{font-size:14px}.activity-card .avatar{align-items:center;border-radius:50%;color:#fff;display:flex;flex:0 0 30px;height:30px;justify-content:center;width:30px}.activity-card .pink{background:linear-gradient(135deg,#ec4899,#f472b6)}.activity-card .purple{background:linear-gradient(135deg,#8b5cf6,#a78bfa)}.activity-card .blue{background:linear-gradient(135deg,#3b82f6,#60a5fa)}.activity-card .green{background:linear-gradient(135deg,#10b981,#34d399)}.activity-card .orange{background:linear-gradient(135deg,#f97316,#fb923c)}.activity-card .text p{color:#6b7280;font-size:12px;margin:2px 0 0}.activity-card .time{color:#94a3b8;font-size:10px;margin-left:auto}.lobby-activity-wp{backdrop-filter:blur(12px);background-color:hsla(0,0%,100%,.4);border:1px solid hsla(0,0%,100%,.2);border-radius:25px;box-shadow:0 1px 3px 0 #0000001a;margin-top:50px;padding:8px}.lobby-close-icon{align-items:center;background-color:color-mix(in oklab,#000 80%,transparent);border-radius:50%;color:#fff;cursor:pointer;display:flex;height:34px;justify-content:center;position:fixed;right:30px;top:30px;width:34px;z-index:99}.lobby-close-icon svg{height:20px;width:20px}@media screen and (max-width:1600px){.cb-lobby-main{border-radius:30px;padding:50px}.title-wp h2{font-size:48px;margin-bottom:12px}.sub-title{font-size:16px}.title-wp{margin-top:20px}.lobby-link-section{margin-top:30px}.offer-box-content h3{font-size:26px}.lobby-offer-box{gap:24px;padding:15px}.cb-lobby-top{gap:80px}.group-info-box{border-radius:20px;padding:22px}.team-card{margin-top:30px}.team-card .team-members{margin-top:12px}.lobby-activity-wp{margin-top:40px}.lobby-close-icon{height:30px;top:20px;width:30px}}@media screen and (max-width:1280px){.cb-lobby-main,.cb-lobby-main-wp{padding:40px}.title-wp h2{font-size:42px}.cb-lobby-top{gap:60px}}@media screen and (max-width:1120px){.title-wp h2{font-size:38px}}@media screen and (max-width:991px){.cb-lobby-top{gap:30px;grid-template-columns:1fr}.cb-lobby-main{border-radius:15px;padding:30px}.cb-lobby-main-wp{padding:30px}.lobby-close-icon{right:20px}.lobby-link-box{border-radius:10px}.share-btn{border-radius:8px}.offer-box-content h3{font-size:24px}.lobby-activity-wp,.lobby-offer-box,.time-card{border-radius:15px;margin-top:20px}.live-activity-wrapper{border-radius:10px}.group-info-box{border-radius:15px}}@media screen and (max-width:767px){.link-share-wrapper{flex-direction:column!important}}@media screen and (max-width:575px){.cb-lobby-main,.cb-lobby-main-wp{padding:20px}.title-wp h2{font-size:30px}.lobby-link-text{font-size:11px;margin-bottom:4px}.lobby-link-url{font-size:14px}.lobby-link-box{min-height:48px;padding:12px 16px}.link-share-wrapper{gap:10px}.share-btn{border-radius:8px;font-size:13px;height:48px;min-width:auto;padding:0 14px}.lobby-offer-box{padding:10px}.offer-box-content h3{font-size:20px}.offer-box-content .reward-text{font-size:13px}.group-info-box{padding:13px}.progress-header .title,.team-card .team-title span{font-size:13px}.team-card .member{height:40px;width:40px}.team-card .member:after{height:8px;width:8px}.team-card .team-members{gap:10px;margin-top:12px}.time-card{padding:13px}.team-card{margin-top:22px}.activity-card .text{font-size:12px}.activity-card .text p{font-size:11px}.live-activity-header .title{font-size:12px}.time-card .time-value{font-size:20px}}@media screen and (max-width:480px){.cb-lobby-main-wp{padding:20px 12px}.cb-lobby-main{padding:15px 12px}.lobby-status{font-size:9px}.lobby-number{font-size:10px}.title-wp h2{font-size:28px;margin-bottom:7px}.sub-title{font-size:14px}.lobby-link-section{gap:10px;margin-top:20px}.lobby-offer-box{gap:12px}.offer-box-icon{height:45px;width:45px}.offer-box-content .reward-text,.offer-lock-status span{font-size:12px}.cb-lobby-top{gap:20px}.lobby-close-icon{right:10px;top:10px}.live-activity-header{flex-direction:column;gap:5px}.activity-card{border-radius:9px;padding:6px}}.share-overlay{align-items:center;background:rgba(0,0,0,.45);display:flex;inset:0;justify-content:center;opacity:0;position:fixed;transition:.3s ease;visibility:hidden;z-index:999}.share-overlay.active{opacity:1;visibility:visible}.share-popup{background:#fff;border-radius:18px;max-height:90%;overflow:auto;padding:24px;position:relative;transform:translateY(30px);transition:.35s ease;width:420px}.share-overlay.active .share-popup{transform:translateY(0)}.share-popup .close-btn{align-items:center;background:#f3f4f6;border:none;border-radius:50%;cursor:pointer;display:flex;height:32px;justify-content:center;position:absolute;right:14px;top:14px;transition:.3s;width:32px}.share-popup .close-btn:hover{background:#eeecec}.share-popup h2{font-size:22px;font-weight:600;line-height:1;margin-bottom:10px}.share-popup .subtitle{color:#4a5565;font-size:14px;margin:6px 0 30px}.share-popup .share-grid{display:grid;gap:14px;grid-template-columns:repeat(2,1fr)}.share-popup .share-card{align-items:center;background:#f2f6f9;border-radius:14px;cursor:pointer;display:flex;flex-direction:column;padding:16px;position:relative;text-align:center;transition:.25s ease}.share-popup .share-card:hover{transform:translateY(-3px)}.share-popup .share-card .icon{align-items:center;background:#1877f2;border-radius:50%;color:#fff;display:flex;font-size:30px;height:50px;justify-content:center;margin-bottom:8px;text-align:center;width:50px}.share-popup .share-card span{font-size:13px;font-weight:500}.share-popup .share-card.whatsapp{background:#ecfdf5;border:2px solid #22c55e;color:#22c55e}.share-popup .share-card.whatsapp .icon{background:#22c55e}.share-popup .share-card .badge{background:#2563eb;border-radius:12px;color:#fff;font-size:11px;padding:4px 10px;position:absolute;right:10px;top:-8px}.share-popup .link-box{background:#fbf9fa;border:1px solid #ebe6e7;border-radius:14px;margin-top:18px;padding:14px}.share-popup .link-box label{color:#64748b;font-size:13px}.share-popup .link-row{display:flex;gap:8px;margin-top:6px}.share-popup .link-row input{background:transparent;border:none;color:#334155;flex:1;font-size:13px;letter-spacing:.8px;line-height:1.2;outline:none}.share-popup .link-row button{align-items:center;background:#fff;border:1px solid #ebe6e7;border-radius:10px;cursor:pointer;display:flex;height:35px;justify-content:center;padding:6px 8px;width:35px}.share-popup .success{color:#2563eb;display:block;font-size:12px;margin-top:6px;opacity:0;transition:opacity .3s}.share-popup .success.show{opacity:1}.share-popup .footer-text{color:#64748b;font-size:12px;margin-top:14px;text-align:center}.share-popup .share-card.twitter .icon{background:#000}.share-popup .share-card.facebook .icon{background:#1877f2}.share-popup .share-card.sms .icon{background:#059669}.share-popup .share-card.copied .icon{background:#2563eb}@keyframes entrance-fade-in{0%{opacity:0}to{opacity:1}}@keyframes entrance-scale-in{0%{opacity:0;transform:scale(.9) translateY(20px)}to{opacity:1;transform:scale(1) translateY(0)}}@keyframes entrance-text-fade-in{0%{opacity:0}to{opacity:1}}@keyframes exit-blur-scale{0%{filter:blur(0);opacity:1;transform:scale(1)}to{filter:blur(10px);opacity:0;transform:scale(1.1)}}@keyframes pulse-dot{0%,to{opacity:1}50%{opacity:.5}}.entrance-animation-overlay{align-items:center;animation:entrance-fade-in .8s ease-in-out forwards;background-color:#0f172a;color:#fff;display:flex;flex-direction:column;inset:0;justify-content:center;position:fixed;z-index:9999}.entrance-animation-overlay.exit{animation:exit-blur-scale .8s ease-in-out forwards}.entrance-content{align-items:center;animation:entrance-scale-in .5s ease-out .2s both;display:flex;flex-direction:column}.entrance-icon-box{align-items:center;background:#2563eb;border-radius:16px;box-shadow:0 10px 25px rgba(37,99,235,.2);display:flex;height:64px;justify-content:center;margin-bottom:24px;width:64px}.entrance-icon-box svg{color:#fff;height:32px;width:32px}.entrance-title{font-size:32px;font-weight:700;letter-spacing:-.5px;margin-bottom:12px}@media (min-width:768px){.entrance-title{font-size:48px}}.entrance-message{align-items:center;animation:entrance-text-fade-in .5s ease-out .5s both;color:#60a5fa;display:flex;font-size:18px;font-weight:500;gap:8px}.entrance-pulse-dot{animation:pulse-dot 1.5s ease-in-out infinite;background-color:#60a5fa;border-radius:50%;height:8px;width:8px}";
2163
2174
  styleInject(css_248z);
2164
2175
 
2165
2176
  /// <reference lib="dom" />
2177
+ const CONTACT_PROMPT_TITLE = "Protect your group spot";
2178
+ const CONTACT_PROMPT_SUBTITLE = "Add your email or phone so we can help you recover your group membership if you leave accidentally.";
2179
+ const CONTACT_PROMPT_PRIMARY_CTA = "Protect my spot";
2180
+ const CONTACT_PROMPT_REMIND_CTA = "Remind me later";
2181
+ const CONTACT_PROMPT_INVALID_INPUT = "Please enter a valid email or phone number.";
2182
+ const CONTACT_PROMPT_SAVE_ERROR = "Could not save contact right now. Please try again.";
2183
+ const CONTACT_PROTECTED_TOAST = "Spot protected. We can help recover your group membership.";
2184
+ const LEAVE_WARNING_TITLE = "Before you leave";
2185
+ const LEAVE_WARNING_SUBTITLE = "If you leave now without adding contact, you may lose this group spot and may not be able to rejoin the same group.";
2166
2186
  /**
2167
2187
  * LobbyModal - Renders and manages the group buying lobby modal
2168
2188
  */
2169
2189
  class LobbyModal {
2170
- constructor(data, callbacks, apiClient, socketManager = null, debug = false) {
2190
+ constructor(data, callbacks, apiClient, socketManager = null, analyticsClient = null, debug = false) {
2171
2191
  this.modalElement = null;
2172
2192
  this.timerInterval = null;
2173
2193
  this.activityInterval = null;
@@ -2176,6 +2196,17 @@ var CoBuySDK = (function (exports) {
2176
2196
  this.currentGroupId = null;
2177
2197
  this.shareOverlay = null;
2178
2198
  this.keyboardHandler = null;
2199
+ this.leaveFlowInProgress = false;
2200
+ this.leaveSignalSent = false;
2201
+ this.hasContactProtection = false;
2202
+ this.initialContactPromptTimer = null;
2203
+ this.contactPromptOverlay = null;
2204
+ this.leaveLoaderOverlay = null;
2205
+ this.beforeUnloadHandler = null;
2206
+ this.pageHideHandler = null;
2207
+ this.visibilityChangeHandler = null;
2208
+ this.CONTACT_PROTECTION_PREFIX = "cobuy_contact_protection";
2209
+ this.LAST_LEFT_GROUP_PREFIX = "cobuy_last_left_group";
2179
2210
  /**
2180
2211
  * Handle socket group update events
2181
2212
  */
@@ -2267,6 +2298,7 @@ var CoBuySDK = (function (exports) {
2267
2298
  this.logger = new Logger(debug);
2268
2299
  this.apiClient = apiClient;
2269
2300
  this.socketManager = socketManager;
2301
+ this.analyticsClient = analyticsClient;
2270
2302
  // Log the group data being passed into the modal
2271
2303
  this.logger.info("LobbyModal initialized with group data", {
2272
2304
  groupId: data.groupId,
@@ -2278,14 +2310,385 @@ var CoBuySDK = (function (exports) {
2278
2310
  timeLeft: data.timeLeft,
2279
2311
  offlineRedemption: data.offlineRedemption,
2280
2312
  });
2281
- this.data = Object.assign({ groupNumber: "1000", status: "active", progress: 80, currentMembers: 4, totalMembers: 5, timeLeft: 1390, discount: "20% OFF", isLocked: true, activities: this.getDefaultActivities() }, data);
2313
+ this.data = Object.assign({ groupNumber: "1000", status: "active", progress: 80, currentMembers: 4, totalMembers: 5, timeLeft: 1390, discount: "20% OFF", isLocked: true, activities: this.getDefaultActivities(), redemptionMethod: "online" }, data);
2282
2314
  // Normalize optional flags so undefined values don't override defaults
2283
2315
  this.data.isLocked = this.computeIsLocked(this.data);
2284
2316
  if (!this.data.activities || !Array.isArray(this.data.activities)) {
2285
2317
  this.data.activities = this.getDefaultActivities();
2286
2318
  }
2319
+ this.hasContactProtection = this.readContactProtectionState();
2287
2320
  this.callbacks = callbacks;
2288
2321
  }
2322
+ getSessionId() {
2323
+ var _a;
2324
+ return ((_a = this.apiClient) === null || _a === void 0 ? void 0 : _a.getSessionId()) || "anonymous";
2325
+ }
2326
+ getContactProtectionStorageKey() {
2327
+ return `${this.CONTACT_PROTECTION_PREFIX}:${this.getSessionId()}:${this.data.productId}`;
2328
+ }
2329
+ getLastLeftGroupStorageKey() {
2330
+ return `${this.LAST_LEFT_GROUP_PREFIX}:${this.getSessionId()}:${this.data.productId}`;
2331
+ }
2332
+ readContactProtectionState() {
2333
+ if (typeof window === "undefined" || !window.localStorage) {
2334
+ return false;
2335
+ }
2336
+ try {
2337
+ return window.localStorage.getItem(this.getContactProtectionStorageKey()) === "1";
2338
+ }
2339
+ catch (_a) {
2340
+ return false;
2341
+ }
2342
+ }
2343
+ persistContactProtectionState(value) {
2344
+ this.hasContactProtection = value;
2345
+ if (typeof window === "undefined" || !window.localStorage) {
2346
+ return;
2347
+ }
2348
+ try {
2349
+ const key = this.getContactProtectionStorageKey();
2350
+ if (value) {
2351
+ window.localStorage.setItem(key, "1");
2352
+ }
2353
+ else {
2354
+ window.localStorage.removeItem(key);
2355
+ }
2356
+ }
2357
+ catch (_a) {
2358
+ // Ignore storage errors (private mode, quota exceeded, etc.)
2359
+ }
2360
+ }
2361
+ persistLastLeftGroup(groupId) {
2362
+ if (typeof window === "undefined" || !window.localStorage || !groupId) {
2363
+ return;
2364
+ }
2365
+ try {
2366
+ window.localStorage.setItem(this.getLastLeftGroupStorageKey(), JSON.stringify({
2367
+ groupId,
2368
+ productId: this.data.productId,
2369
+ leftAt: Date.now(),
2370
+ }));
2371
+ }
2372
+ catch (_a) {
2373
+ // Ignore storage errors
2374
+ }
2375
+ }
2376
+ clearInitialContactPromptTimer() {
2377
+ if (this.initialContactPromptTimer !== null) {
2378
+ window.clearTimeout(this.initialContactPromptTimer);
2379
+ this.initialContactPromptTimer = null;
2380
+ }
2381
+ }
2382
+ clearContactPromptOverlay() {
2383
+ if (this.contactPromptOverlay) {
2384
+ this.contactPromptOverlay.remove();
2385
+ this.contactPromptOverlay = null;
2386
+ }
2387
+ }
2388
+ showBlockingLoader(message) {
2389
+ if (!this.modalElement) {
2390
+ return;
2391
+ }
2392
+ this.hideBlockingLoader();
2393
+ const overlay = document.createElement("div");
2394
+ overlay.className = "lobby-blocking-loader-overlay";
2395
+ const card = document.createElement("div");
2396
+ card.className = "lobby-blocking-loader-card";
2397
+ const spinner = document.createElement("div");
2398
+ spinner.className = "lobby-blocking-loader-spinner";
2399
+ const text = document.createElement("p");
2400
+ text.className = "lobby-blocking-loader-text";
2401
+ text.textContent = message;
2402
+ card.appendChild(spinner);
2403
+ card.appendChild(text);
2404
+ overlay.appendChild(card);
2405
+ this.modalElement.appendChild(overlay);
2406
+ this.leaveLoaderOverlay = overlay;
2407
+ }
2408
+ hideBlockingLoader() {
2409
+ if (this.leaveLoaderOverlay) {
2410
+ this.leaveLoaderOverlay.remove();
2411
+ this.leaveLoaderOverlay = null;
2412
+ }
2413
+ }
2414
+ updateContactProtectionUI() {
2415
+ const banner = document.getElementById("lobbyContactProtectionBanner");
2416
+ const explicitLeaveContainer = document.getElementById("lobbyProtectedLeaveContainer");
2417
+ if (!banner)
2418
+ return;
2419
+ const canShowContactActions = this.data.status !== "complete" && Boolean(this.apiClient);
2420
+ if (!canShowContactActions) {
2421
+ banner.style.display = "none";
2422
+ if (explicitLeaveContainer) {
2423
+ explicitLeaveContainer.style.display = "none";
2424
+ }
2425
+ return;
2426
+ }
2427
+ if (this.hasContactProtection) {
2428
+ banner.style.display = "none";
2429
+ if (explicitLeaveContainer) {
2430
+ explicitLeaveContainer.style.display = "flex";
2431
+ }
2432
+ return;
2433
+ }
2434
+ banner.style.display = "flex";
2435
+ if (explicitLeaveContainer) {
2436
+ explicitLeaveContainer.style.display = "none";
2437
+ }
2438
+ }
2439
+ showToastMessage(message) {
2440
+ if (!this.modalElement) {
2441
+ return;
2442
+ }
2443
+ const existing = this.modalElement.querySelector(".lobby-contact-toast");
2444
+ if (existing) {
2445
+ existing.remove();
2446
+ }
2447
+ const toast = document.createElement("div");
2448
+ toast.className = "lobby-contact-toast";
2449
+ toast.textContent = message;
2450
+ this.modalElement.appendChild(toast);
2451
+ window.setTimeout(() => {
2452
+ toast.remove();
2453
+ }, 2400);
2454
+ }
2455
+ trackAnalyticsEvent(eventName, metadata) {
2456
+ if (!this.analyticsClient) {
2457
+ return;
2458
+ }
2459
+ this.analyticsClient
2460
+ .trackEvent(eventName, this.data.productId, Object.assign({ groupId: this.currentGroupId || this.data.groupId }, metadata))
2461
+ .catch((error) => {
2462
+ this.logger.warn(`[Analytics] Failed to track ${eventName}`, error);
2463
+ });
2464
+ }
2465
+ async saveContactValue(contactValue, promptSource) {
2466
+ const trimmed = contactValue.trim();
2467
+ if (!trimmed || !this.apiClient) {
2468
+ return false;
2469
+ }
2470
+ const contactType = this.inferContactType(trimmed);
2471
+ if (!contactType) {
2472
+ window.alert(CONTACT_PROMPT_INVALID_INPUT);
2473
+ return false;
2474
+ }
2475
+ const payload = contactType === "phone"
2476
+ ? { type: "phone", value: trimmed.replace(/\D/g, "") }
2477
+ : { type: "email", value: trimmed };
2478
+ const result = await this.apiClient.setContact(payload);
2479
+ if (!result.success) {
2480
+ this.logger.warn("Failed to save lobby contact", result.error);
2481
+ window.alert(CONTACT_PROMPT_SAVE_ERROR);
2482
+ return false;
2483
+ }
2484
+ this.persistContactProtectionState(true);
2485
+ this.trackAnalyticsEvent("CONTACT_INFO_SAVED", {
2486
+ promptSource,
2487
+ contactType,
2488
+ protectionState: "protected",
2489
+ });
2490
+ this.updateContactProtectionUI();
2491
+ this.showToastMessage(CONTACT_PROTECTED_TOAST);
2492
+ return true;
2493
+ }
2494
+ openContactProtectionPrompt(source) {
2495
+ if (typeof document === "undefined" || !this.modalElement) {
2496
+ return Promise.resolve("cancel");
2497
+ }
2498
+ this.clearContactPromptOverlay();
2499
+ this.trackAnalyticsEvent("CONTACT_PROMPT_SHOWN", {
2500
+ promptSource: source,
2501
+ protectionState: "unprotected",
2502
+ });
2503
+ return new Promise((resolve) => {
2504
+ var _a;
2505
+ const overlay = document.createElement("div");
2506
+ overlay.className = "lobby-contact-overlay";
2507
+ const card = document.createElement("div");
2508
+ card.className = "lobby-contact-card";
2509
+ const title = document.createElement("h3");
2510
+ title.className = "lobby-contact-title";
2511
+ title.textContent = CONTACT_PROMPT_TITLE;
2512
+ const subtitle = document.createElement("p");
2513
+ subtitle.className = "lobby-contact-subtitle";
2514
+ subtitle.textContent = CONTACT_PROMPT_SUBTITLE;
2515
+ const input = document.createElement("input");
2516
+ input.type = "text";
2517
+ input.className = "lobby-contact-input";
2518
+ input.placeholder = "Email or phone";
2519
+ input.autocomplete = "email";
2520
+ const actions = document.createElement("div");
2521
+ actions.className = "lobby-contact-actions";
2522
+ const primary = document.createElement("button");
2523
+ primary.type = "button";
2524
+ primary.className = "lobby-contact-primary";
2525
+ primary.textContent = CONTACT_PROMPT_PRIMARY_CTA;
2526
+ const secondary = document.createElement("button");
2527
+ secondary.type = "button";
2528
+ secondary.className = "lobby-contact-secondary";
2529
+ secondary.textContent = source === "leave-warning" ? "Cancel" : CONTACT_PROMPT_REMIND_CTA;
2530
+ const cleanupAndResolve = (result) => {
2531
+ this.clearContactPromptOverlay();
2532
+ resolve(result);
2533
+ };
2534
+ primary.addEventListener("click", async () => {
2535
+ const originalLabel = primary.textContent;
2536
+ primary.disabled = true;
2537
+ secondary.disabled = true;
2538
+ input.disabled = true;
2539
+ primary.classList.add("is-loading");
2540
+ primary.textContent = "Saving...";
2541
+ try {
2542
+ const saved = await this.saveContactValue(input.value, source);
2543
+ if (saved) {
2544
+ cleanupAndResolve("saved");
2545
+ }
2546
+ }
2547
+ finally {
2548
+ if (this.contactPromptOverlay) {
2549
+ primary.disabled = false;
2550
+ secondary.disabled = false;
2551
+ input.disabled = false;
2552
+ primary.classList.remove("is-loading");
2553
+ primary.textContent = originalLabel || CONTACT_PROMPT_PRIMARY_CTA;
2554
+ }
2555
+ }
2556
+ });
2557
+ secondary.addEventListener("click", () => {
2558
+ if (source !== "leave-warning") {
2559
+ this.trackAnalyticsEvent("CONTACT_PROMPT_DEFERRED", {
2560
+ promptSource: source,
2561
+ protectionState: "unprotected",
2562
+ });
2563
+ }
2564
+ cleanupAndResolve(source === "leave-warning" ? "cancel" : "later");
2565
+ });
2566
+ overlay.addEventListener("click", (event) => {
2567
+ if (event.target === overlay) {
2568
+ if (source !== "leave-warning") {
2569
+ this.trackAnalyticsEvent("CONTACT_PROMPT_DEFERRED", {
2570
+ promptSource: source,
2571
+ protectionState: "unprotected",
2572
+ });
2573
+ }
2574
+ cleanupAndResolve(source === "leave-warning" ? "cancel" : "later");
2575
+ }
2576
+ });
2577
+ actions.appendChild(primary);
2578
+ actions.appendChild(secondary);
2579
+ card.appendChild(title);
2580
+ card.appendChild(subtitle);
2581
+ card.appendChild(input);
2582
+ card.appendChild(actions);
2583
+ overlay.appendChild(card);
2584
+ (_a = this.modalElement) === null || _a === void 0 ? void 0 : _a.appendChild(overlay);
2585
+ this.contactPromptOverlay = overlay;
2586
+ window.setTimeout(() => input.focus(), 0);
2587
+ });
2588
+ }
2589
+ openUnprotectedLeaveWarning() {
2590
+ if (typeof document === "undefined" || !this.modalElement) {
2591
+ return Promise.resolve("cancel");
2592
+ }
2593
+ this.clearContactPromptOverlay();
2594
+ return new Promise((resolve) => {
2595
+ var _a;
2596
+ const overlay = document.createElement("div");
2597
+ overlay.className = "lobby-contact-overlay";
2598
+ const card = document.createElement("div");
2599
+ card.className = "lobby-contact-card";
2600
+ const title = document.createElement("h3");
2601
+ title.className = "lobby-contact-title";
2602
+ title.textContent = LEAVE_WARNING_TITLE;
2603
+ const subtitle = document.createElement("p");
2604
+ subtitle.className = "lobby-contact-subtitle";
2605
+ subtitle.textContent = LEAVE_WARNING_SUBTITLE;
2606
+ const actions = document.createElement("div");
2607
+ actions.className = "lobby-contact-actions";
2608
+ const addContactBtn = document.createElement("button");
2609
+ addContactBtn.type = "button";
2610
+ addContactBtn.className = "lobby-contact-primary";
2611
+ addContactBtn.textContent = "Add contact first";
2612
+ const leaveBtn = document.createElement("button");
2613
+ leaveBtn.type = "button";
2614
+ leaveBtn.className = "lobby-contact-danger";
2615
+ leaveBtn.textContent = "Leave anyway";
2616
+ const cancelBtn = document.createElement("button");
2617
+ cancelBtn.type = "button";
2618
+ cancelBtn.className = "lobby-contact-secondary";
2619
+ cancelBtn.textContent = "Cancel";
2620
+ const cleanup = (result) => {
2621
+ this.clearContactPromptOverlay();
2622
+ resolve(result);
2623
+ };
2624
+ addContactBtn.addEventListener("click", () => cleanup("add_contact"));
2625
+ leaveBtn.addEventListener("click", () => cleanup("leave"));
2626
+ cancelBtn.addEventListener("click", () => cleanup("cancel"));
2627
+ overlay.addEventListener("click", (event) => {
2628
+ if (event.target === overlay) {
2629
+ cleanup("cancel");
2630
+ }
2631
+ });
2632
+ actions.appendChild(addContactBtn);
2633
+ actions.appendChild(leaveBtn);
2634
+ actions.appendChild(cancelBtn);
2635
+ card.appendChild(title);
2636
+ card.appendChild(subtitle);
2637
+ card.appendChild(actions);
2638
+ overlay.appendChild(card);
2639
+ (_a = this.modalElement) === null || _a === void 0 ? void 0 : _a.appendChild(overlay);
2640
+ this.contactPromptOverlay = overlay;
2641
+ });
2642
+ }
2643
+ scheduleInitialContactPrompt() {
2644
+ if (!this.modalElement ||
2645
+ !this.shouldRunLeaveFlow() ||
2646
+ this.hasContactProtection ||
2647
+ !this.apiClient) {
2648
+ return;
2649
+ }
2650
+ this.clearInitialContactPromptTimer();
2651
+ this.initialContactPromptTimer = window.setTimeout(async () => {
2652
+ this.initialContactPromptTimer = null;
2653
+ if (!this.modalElement || this.hasContactProtection) {
2654
+ return;
2655
+ }
2656
+ await this.openContactProtectionPrompt("initial");
2657
+ this.updateContactProtectionUI();
2658
+ }, 2000);
2659
+ }
2660
+ async leaveGroupExplicitly() {
2661
+ var _a, _b;
2662
+ if (!this.apiClient || !this.currentGroupId || this.leaveFlowInProgress) {
2663
+ return;
2664
+ }
2665
+ this.leaveFlowInProgress = true;
2666
+ try {
2667
+ this.showBlockingLoader("Leaving group...");
2668
+ const leaveResult = await this.apiClient.leaveGroup(this.currentGroupId, {
2669
+ leave_source: "close_icon",
2670
+ leave_reason: "voluntary_with_contact",
2671
+ });
2672
+ if (!leaveResult.success) {
2673
+ this.logger.warn("Explicit leave group failed", leaveResult.error);
2674
+ this.hideBlockingLoader();
2675
+ window.alert("Could not leave the group right now. Please try again.");
2676
+ return;
2677
+ }
2678
+ this.leaveSignalSent = true;
2679
+ this.persistLastLeftGroup(((_b = (_a = leaveResult.data) === null || _a === void 0 ? void 0 : _a.group) === null || _b === void 0 ? void 0 : _b.id) || this.currentGroupId);
2680
+ this.trackAnalyticsEvent("PROTECTED_USER_EXPLICIT_LEAVE", {
2681
+ leaveSource: "close_icon",
2682
+ leaveReason: "voluntary_with_contact",
2683
+ protectionState: "protected",
2684
+ });
2685
+ this.close({ skipLeaveFlow: true });
2686
+ }
2687
+ finally {
2688
+ this.hideBlockingLoader();
2689
+ this.leaveFlowInProgress = false;
2690
+ }
2691
+ }
2289
2692
  /**
2290
2693
  * Derive lock state from data so UI reflects completion
2291
2694
  */
@@ -2602,6 +3005,7 @@ var CoBuySDK = (function (exports) {
2602
3005
  * Create connected section (subtitle + link + share)
2603
3006
  */
2604
3007
  createConnectedSection() {
3008
+ var _a, _b;
2605
3009
  const connectedSection = document.createElement("div");
2606
3010
  connectedSection.className = "connected-section";
2607
3011
  connectedSection.id = "lobbyConnectedSection";
@@ -2612,18 +3016,59 @@ var CoBuySDK = (function (exports) {
2612
3016
  subtitle.id = "lobbySubtitleText";
2613
3017
  subtitle.textContent = titleContent.subtitle;
2614
3018
  connectedSection.appendChild(subtitle);
3019
+ const contactBanner = document.createElement("div");
3020
+ contactBanner.className = "lobby-contact-protection-banner";
3021
+ contactBanner.id = "lobbyContactProtectionBanner";
3022
+ const contactCopy = document.createElement("p");
3023
+ contactCopy.className = "lobby-contact-protection-copy";
3024
+ contactCopy.textContent =
3025
+ "Spot not protected. Add contact so we can help recover your group membership.";
3026
+ const contactAction = document.createElement("button");
3027
+ contactAction.type = "button";
3028
+ contactAction.className = "lobby-contact-protection-btn";
3029
+ contactAction.textContent = "Add contact";
3030
+ contactAction.addEventListener("click", async () => {
3031
+ await this.openContactProtectionPrompt("banner");
3032
+ this.updateContactProtectionUI();
3033
+ });
3034
+ contactBanner.appendChild(contactCopy);
3035
+ contactBanner.appendChild(contactAction);
3036
+ connectedSection.appendChild(contactBanner);
3037
+ const protectedLeaveContainer = document.createElement("div");
3038
+ protectedLeaveContainer.className = "lobby-protected-leave-container";
3039
+ protectedLeaveContainer.id = "lobbyProtectedLeaveContainer";
3040
+ const protectedLeaveText = document.createElement("p");
3041
+ protectedLeaveText.className = "lobby-protected-leave-copy";
3042
+ protectedLeaveText.textContent = "You are protected and still part of this group.";
3043
+ const protectedLeaveAction = document.createElement("button");
3044
+ protectedLeaveAction.type = "button";
3045
+ protectedLeaveAction.className = "lobby-protected-leave-btn";
3046
+ protectedLeaveAction.textContent = "Leave group";
3047
+ protectedLeaveAction.addEventListener("click", () => {
3048
+ void this.leaveGroupExplicitly();
3049
+ });
3050
+ protectedLeaveContainer.appendChild(protectedLeaveText);
3051
+ protectedLeaveContainer.appendChild(protectedLeaveAction);
3052
+ connectedSection.appendChild(protectedLeaveContainer);
2615
3053
  // Check if group is fulfilled and has offline redemption
2616
3054
  const isComplete = !this.computeIsLocked(this.data);
2617
3055
  const hasOfflineRedemption = isComplete &&
2618
3056
  this.data.offlineRedemption &&
2619
- isValidOfflineRedemption(this.data.offlineRedemption);
3057
+ isValidOfflineRedemption(this.data.offlineRedemption) &&
3058
+ ((_a = this.data.redemptionMethod) !== null && _a !== void 0 ? _a : "online") !== "online";
2620
3059
  if (hasOfflineRedemption) {
2621
- // Show offline redemption view with integrated actions
3060
+ // Complete + offline/both: show offline redemption section
2622
3061
  const offlineSection = this.createOfflineRedemptionSection(this.data.offlineRedemption);
2623
3062
  connectedSection.appendChild(offlineSection);
2624
3063
  }
3064
+ else if (isComplete && ((_b = this.data.redemptionMethod) !== null && _b !== void 0 ? _b : "online") !== "offline") {
3065
+ // Complete + online/both (no offline redemption data): show only checkout CTA
3066
+ const checkoutBtn = this.createOnlineCheckoutButton();
3067
+ connectedSection.appendChild(checkoutBtn);
3068
+ this.injectOfflineRedemptionStyles();
3069
+ }
2625
3070
  else {
2626
- // Show link and share container
3071
+ // Group not yet complete: show link and share
2627
3072
  const linkShareContainer = document.createElement("div");
2628
3073
  linkShareContainer.className = "link-share-container";
2629
3074
  const linkWp = this.createLinkSection();
@@ -2667,6 +3112,23 @@ var CoBuySDK = (function (exports) {
2667
3112
  linkShareWrapper.appendChild(shareBtnInner);
2668
3113
  return linkShareWrapper;
2669
3114
  }
3115
+ /**
3116
+ * Create a standalone "Checkout Online" button for the link/share section
3117
+ */
3118
+ createOnlineCheckoutButton() {
3119
+ const btn = document.createElement("button");
3120
+ btn.className = "offline-online-checkout-btn lobby-online-checkout-btn";
3121
+ btn.textContent = "Checkout Online";
3122
+ btn.style.marginTop = "10px";
3123
+ btn.style.width = "100%";
3124
+ btn.addEventListener("click", () => {
3125
+ this.close();
3126
+ window.setTimeout(() => {
3127
+ this.triggerContinueToCheckout();
3128
+ }, 0);
3129
+ });
3130
+ return btn;
3131
+ }
2670
3132
  /**
2671
3133
  * Create offline redemption section
2672
3134
  */
@@ -2731,14 +3193,16 @@ var CoBuySDK = (function (exports) {
2731
3193
  onlineCheckoutBtn.className = "offline-online-checkout-btn";
2732
3194
  onlineCheckoutBtn.textContent = "Checkout Online";
2733
3195
  onlineCheckoutBtn.addEventListener("click", () => {
2734
- this.close();
3196
+ this.close({ skipLeaveFlow: true });
2735
3197
  // Ensure modal closes before triggering checkout intent
2736
3198
  window.setTimeout(() => {
2737
3199
  this.triggerContinueToCheckout();
2738
3200
  }, 0);
2739
3201
  });
2740
3202
  actionsRow.appendChild(downloadQRBtn);
2741
- actionsRow.appendChild(onlineCheckoutBtn);
3203
+ if (this.data.redemptionMethod !== "offline") {
3204
+ actionsRow.appendChild(onlineCheckoutBtn);
3205
+ }
2742
3206
  section.appendChild(topRow);
2743
3207
  section.appendChild(expiryInfo);
2744
3208
  section.appendChild(actionsRow);
@@ -3644,6 +4108,10 @@ var CoBuySDK = (function (exports) {
3644
4108
  this.logger.info(`Lobby modal opened for product: ${this.data.productId}`);
3645
4109
  // Set up keyboard accessibility (focus trap, ESC to close)
3646
4110
  this.setupKeyboardAccessibility();
4111
+ // Register lifecycle-based dropoff handling for browser/tab close.
4112
+ this.registerLifecycleLeaveHandlers();
4113
+ this.updateContactProtectionUI();
4114
+ this.scheduleInitialContactPrompt();
3647
4115
  });
3648
4116
  }
3649
4117
  /**
@@ -3709,19 +4177,166 @@ var CoBuySDK = (function (exports) {
3709
4177
  this.keyboardHandler = null;
3710
4178
  }
3711
4179
  }
4180
+ registerLifecycleLeaveHandlers() {
4181
+ if (typeof window === "undefined" || typeof document === "undefined") {
4182
+ return;
4183
+ }
4184
+ if (!this.shouldRunLeaveFlow()) {
4185
+ return;
4186
+ }
4187
+ if (!this.beforeUnloadHandler) {
4188
+ this.beforeUnloadHandler = () => {
4189
+ this.triggerBestEffortLeave("browser_close");
4190
+ };
4191
+ window.addEventListener("beforeunload", this.beforeUnloadHandler);
4192
+ }
4193
+ if (!this.pageHideHandler) {
4194
+ this.pageHideHandler = () => {
4195
+ this.triggerBestEffortLeave("browser_close");
4196
+ };
4197
+ window.addEventListener("pagehide", this.pageHideHandler);
4198
+ }
4199
+ if (!this.visibilityChangeHandler) {
4200
+ this.visibilityChangeHandler = () => {
4201
+ if (document.visibilityState === "hidden") {
4202
+ this.triggerBestEffortLeave("browser_close");
4203
+ }
4204
+ };
4205
+ document.addEventListener("visibilitychange", this.visibilityChangeHandler);
4206
+ }
4207
+ }
4208
+ unregisterLifecycleLeaveHandlers() {
4209
+ if (typeof window === "undefined" || typeof document === "undefined") {
4210
+ return;
4211
+ }
4212
+ if (this.beforeUnloadHandler) {
4213
+ window.removeEventListener("beforeunload", this.beforeUnloadHandler);
4214
+ this.beforeUnloadHandler = null;
4215
+ }
4216
+ if (this.pageHideHandler) {
4217
+ window.removeEventListener("pagehide", this.pageHideHandler);
4218
+ this.pageHideHandler = null;
4219
+ }
4220
+ if (this.visibilityChangeHandler) {
4221
+ document.removeEventListener("visibilitychange", this.visibilityChangeHandler);
4222
+ this.visibilityChangeHandler = null;
4223
+ }
4224
+ }
4225
+ triggerBestEffortLeave(source) {
4226
+ if (this.leaveSignalSent || this.leaveFlowInProgress) {
4227
+ return;
4228
+ }
4229
+ if (this.hasContactProtection) {
4230
+ return;
4231
+ }
4232
+ if (!this.apiClient || !this.currentGroupId || !this.shouldRunLeaveFlow()) {
4233
+ return;
4234
+ }
4235
+ this.leaveSignalSent = true;
4236
+ this.apiClient.leaveGroupBestEffort(this.currentGroupId, {
4237
+ leave_source: source,
4238
+ leave_reason: "voluntary_no_contact",
4239
+ });
4240
+ }
4241
+ shouldRunLeaveFlow() {
4242
+ if (!this.apiClient || !this.currentGroupId) {
4243
+ return false;
4244
+ }
4245
+ // Dropoff handling applies only while group is still active/forming.
4246
+ return this.data.status !== "complete";
4247
+ }
4248
+ inferContactType(value) {
4249
+ const trimmed = value.trim();
4250
+ if (!trimmed)
4251
+ return null;
4252
+ if (trimmed.includes("@")) {
4253
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
4254
+ return emailRegex.test(trimmed) ? "email" : null;
4255
+ }
4256
+ const digitsOnly = trimmed.replace(/\D/g, "");
4257
+ return digitsOnly.length >= 10 && digitsOnly.length <= 15 ? "phone" : null;
4258
+ }
4259
+ async runLeaveFlowAndClose() {
4260
+ var _a, _b;
4261
+ if (this.leaveFlowInProgress)
4262
+ return;
4263
+ this.leaveFlowInProgress = true;
4264
+ try {
4265
+ if (this.hasContactProtection) {
4266
+ this.trackAnalyticsEvent("LOBBY_CLOSED_PROTECTED", {
4267
+ leaveSource: "close_icon",
4268
+ leaveReason: "stay_in_group",
4269
+ protectionState: "protected",
4270
+ });
4271
+ this.close({ skipLeaveFlow: true });
4272
+ return;
4273
+ }
4274
+ let leaveReason = "voluntary_no_contact";
4275
+ const leaveDecision = await this.openUnprotectedLeaveWarning();
4276
+ if (leaveDecision === "cancel") {
4277
+ return;
4278
+ }
4279
+ if (leaveDecision === "add_contact") {
4280
+ const promptResult = await this.openContactProtectionPrompt("leave-warning");
4281
+ if (promptResult === "saved") {
4282
+ this.updateContactProtectionUI();
4283
+ return;
4284
+ }
4285
+ else {
4286
+ return;
4287
+ }
4288
+ }
4289
+ if (this.apiClient && this.currentGroupId) {
4290
+ this.showBlockingLoader("Leaving group...");
4291
+ const leaveResult = await this.apiClient.leaveGroup(this.currentGroupId, {
4292
+ leave_source: "close_icon",
4293
+ leave_reason: leaveReason,
4294
+ });
4295
+ if (!leaveResult.success) {
4296
+ this.logger.warn("Leave group failed", leaveResult.error);
4297
+ this.hideBlockingLoader();
4298
+ window.alert("Could not leave the group right now. Please try again.");
4299
+ return;
4300
+ }
4301
+ this.leaveSignalSent = true;
4302
+ this.persistLastLeftGroup(((_b = (_a = leaveResult.data) === null || _a === void 0 ? void 0 : _a.group) === null || _b === void 0 ? void 0 : _b.id) || this.currentGroupId);
4303
+ this.trackAnalyticsEvent("LOBBY_LEFT_UNPROTECTED", {
4304
+ leaveSource: "close_icon",
4305
+ leaveReason,
4306
+ protectionState: "unprotected",
4307
+ });
4308
+ }
4309
+ this.close({ skipLeaveFlow: true });
4310
+ }
4311
+ finally {
4312
+ this.hideBlockingLoader();
4313
+ this.leaveFlowInProgress = false;
4314
+ }
4315
+ }
3712
4316
  /**
3713
4317
  * Close the modal
3714
4318
  */
3715
- close() {
4319
+ close(options = {}) {
3716
4320
  if (!this.modalElement) {
3717
4321
  this.logger.warn("Modal not open");
3718
4322
  return;
3719
4323
  }
4324
+ if (!options.skipLeaveFlow && this.shouldRunLeaveFlow()) {
4325
+ void this.runLeaveFlowAndClose();
4326
+ return;
4327
+ }
3720
4328
  // Stop timers and animations
3721
4329
  this.stopTimer();
3722
4330
  this.stopActivityAnimation();
3723
4331
  // Remove keyboard event listeners
3724
4332
  this.removeKeyboardAccessibility();
4333
+ // Remove lifecycle handlers for dropoff detection
4334
+ this.unregisterLifecycleLeaveHandlers();
4335
+ this.clearInitialContactPromptTimer();
4336
+ this.clearContactPromptOverlay();
4337
+ this.hideBlockingLoader();
4338
+ // Remove socket listeners to avoid duplicate handlers on reopen
4339
+ this.unsubscribeFromSocketEvents();
3725
4340
  // Remove modal from DOM
3726
4341
  document.body.removeChild(this.modalElement);
3727
4342
  this.modalElement = null;
@@ -3834,29 +4449,47 @@ var CoBuySDK = (function (exports) {
3834
4449
  * Update offline redemption visibility when group is fulfilled
3835
4450
  */
3836
4451
  updateOfflineRedemptionVisibility() {
4452
+ var _a, _b;
3837
4453
  const connectedSection = document.getElementById("lobbyConnectedSection");
3838
4454
  if (!connectedSection)
3839
4455
  return;
3840
4456
  const isComplete = !this.computeIsLocked(this.data);
3841
- const hasOfflineRedemption = this.data.offlineRedemption && isValidOfflineRedemption(this.data.offlineRedemption);
4457
+ const hasOfflineRedemption = this.data.offlineRedemption &&
4458
+ isValidOfflineRedemption(this.data.offlineRedemption) &&
4459
+ ((_a = this.data.redemptionMethod) !== null && _a !== void 0 ? _a : "online") !== "online";
3842
4460
  // Get existing elements
3843
4461
  const existingOffline = connectedSection.querySelector(".offline-redemption-section");
3844
4462
  const existingLink = connectedSection.querySelector(".link-share-container");
4463
+ const existingCheckoutBtn = connectedSection.querySelector(".lobby-online-checkout-btn");
3845
4464
  if (isComplete && hasOfflineRedemption) {
3846
- // Show offline redemption, hide link/share
3847
- if (existingLink) {
4465
+ // Complete + offline/both: show offline section, remove link/share and standalone checkout btn
4466
+ if (existingLink)
3848
4467
  existingLink.remove();
3849
- }
4468
+ if (existingCheckoutBtn)
4469
+ existingCheckoutBtn.remove();
3850
4470
  if (!existingOffline) {
3851
4471
  const offlineSection = this.createOfflineRedemptionSection(this.data.offlineRedemption);
3852
4472
  connectedSection.appendChild(offlineSection);
3853
4473
  }
3854
4474
  }
3855
- else {
3856
- // Show link/share, hide offline redemption
3857
- if (existingOffline) {
4475
+ else if (isComplete && ((_b = this.data.redemptionMethod) !== null && _b !== void 0 ? _b : "online") !== "offline") {
4476
+ // Complete + online/both (no offline data): show only checkout CTA, remove link/share
4477
+ if (existingLink)
4478
+ existingLink.remove();
4479
+ if (existingOffline)
3858
4480
  existingOffline.remove();
4481
+ if (!existingCheckoutBtn) {
4482
+ const checkoutBtn = this.createOnlineCheckoutButton();
4483
+ connectedSection.appendChild(checkoutBtn);
4484
+ this.injectOfflineRedemptionStyles();
3859
4485
  }
4486
+ }
4487
+ else {
4488
+ // Group not yet complete: show link/share, remove offline and checkout btn
4489
+ if (existingOffline)
4490
+ existingOffline.remove();
4491
+ if (existingCheckoutBtn)
4492
+ existingCheckoutBtn.remove();
3860
4493
  if (!existingLink) {
3861
4494
  const linkShareContainer = document.createElement("div");
3862
4495
  linkShareContainer.className = "link-share-container";
@@ -3890,9 +4523,20 @@ var CoBuySDK = (function (exports) {
3890
4523
  }
3891
4524
  window.addEventListener("group:fulfilled", this.handleSocketGroupUpdate);
3892
4525
  window.addEventListener("group:member:joined", this.handleSocketGroupUpdate);
4526
+ window.addEventListener("group:member:left", this.handleSocketGroupUpdate);
3893
4527
  window.addEventListener("group:created", this.handleSocketGroupUpdate);
3894
4528
  this.socketListenerRegistered = true;
3895
4529
  }
4530
+ unsubscribeFromSocketEvents() {
4531
+ if (typeof window === "undefined" || !this.socketListenerRegistered) {
4532
+ return;
4533
+ }
4534
+ window.removeEventListener("group:fulfilled", this.handleSocketGroupUpdate);
4535
+ window.removeEventListener("group:member:joined", this.handleSocketGroupUpdate);
4536
+ window.removeEventListener("group:member:left", this.handleSocketGroupUpdate);
4537
+ window.removeEventListener("group:created", this.handleSocketGroupUpdate);
4538
+ this.socketListenerRegistered = false;
4539
+ }
3896
4540
  /**
3897
4541
  * Create activity item from socket event data
3898
4542
  */
@@ -3923,6 +4567,10 @@ var CoBuySDK = (function (exports) {
3923
4567
  emoji = "🛒";
3924
4568
  action = "started a new group";
3925
4569
  break;
4570
+ case "group:member:left":
4571
+ emoji = "🚪";
4572
+ action = "left the group";
4573
+ break;
3926
4574
  default:
3927
4575
  emoji = "⚡";
3928
4576
  action = "activity in group";
@@ -4395,6 +5043,9 @@ var CoBuySDK = (function (exports) {
4395
5043
  WidgetState["LOADED"] = "loaded";
4396
5044
  WidgetState["ERROR"] = "error";
4397
5045
  })(WidgetState || (WidgetState = {}));
5046
+ const RECOVERY_TOAST_REJOINED = "Rejoined your previous group.";
5047
+ const RECOVERY_TOAST_NEXT_AVAILABLE = "Your previous group was full, so we joined you to the next available group.";
5048
+ const RECOVERY_TOAST_CREATED_NEW = "Your previous group was no longer available, so we created a fresh group for you.";
4398
5049
  /**
4399
5050
  * WidgetRoot handles rendering of the CoBuy widget into a DOM container
4400
5051
  */
@@ -4426,6 +5077,7 @@ var CoBuySDK = (function (exports) {
4426
5077
  this.groupExpiryRefreshTriggered = false; // Track if expiry refresh already triggered for current group
4427
5078
  this.offlineRedemption = null;
4428
5079
  this.offlineRedemptionModal = null;
5080
+ this.campaignRedemptionMethod = "online";
4429
5081
  this.isRendering = false;
4430
5082
  this.renderPromise = null;
4431
5083
  this.liveRegionAnnouncer = null;
@@ -4435,6 +5087,7 @@ var CoBuySDK = (function (exports) {
4435
5087
  this.renderDebounceTimer = null;
4436
5088
  this.pendingRenderOptions = null;
4437
5089
  this.RENDER_DEBOUNCE_MS = 300; // 300ms debounce for rapid re-renders
5090
+ this.LAST_LEFT_GROUP_PREFIX = "cobuy_last_left_group";
4438
5091
  /** Handle backend fulfillment notifications */
4439
5092
  this.handleGroupFulfilledEvent = (event) => {
4440
5093
  const detail = event.detail;
@@ -4478,6 +5131,80 @@ var CoBuySDK = (function (exports) {
4478
5131
  this.handleCTAClick(productId);
4479
5132
  }, 300); // 300ms debounce to prevent double-clicks
4480
5133
  }
5134
+ getRecoveryStorageKey(productId) {
5135
+ var _a;
5136
+ const sessionId = (_a = this.apiClient) === null || _a === void 0 ? void 0 : _a.getSessionId();
5137
+ if (!sessionId || !productId) {
5138
+ return null;
5139
+ }
5140
+ return `${this.LAST_LEFT_GROUP_PREFIX}:${sessionId}:${productId}`;
5141
+ }
5142
+ getStoredRecoveryGroupId(productId) {
5143
+ if (typeof window === "undefined" || !window.localStorage) {
5144
+ return null;
5145
+ }
5146
+ const key = this.getRecoveryStorageKey(productId);
5147
+ if (!key) {
5148
+ return null;
5149
+ }
5150
+ try {
5151
+ const raw = window.localStorage.getItem(key);
5152
+ if (!raw) {
5153
+ return null;
5154
+ }
5155
+ const parsed = JSON.parse(raw);
5156
+ if (!(parsed === null || parsed === void 0 ? void 0 : parsed.groupId) || parsed.productId !== productId) {
5157
+ return null;
5158
+ }
5159
+ return parsed.groupId;
5160
+ }
5161
+ catch (_a) {
5162
+ return null;
5163
+ }
5164
+ }
5165
+ clearStoredRecoveryGroupId(productId) {
5166
+ if (typeof window === "undefined" || !window.localStorage) {
5167
+ return;
5168
+ }
5169
+ const key = this.getRecoveryStorageKey(productId);
5170
+ if (!key) {
5171
+ return;
5172
+ }
5173
+ try {
5174
+ window.localStorage.removeItem(key);
5175
+ }
5176
+ catch (_a) {
5177
+ // Ignore storage issues
5178
+ }
5179
+ }
5180
+ showRecoveryToast(message) {
5181
+ if (typeof document === "undefined") {
5182
+ return;
5183
+ }
5184
+ const existing = document.getElementById("cobuy-recovery-toast");
5185
+ if (existing) {
5186
+ existing.remove();
5187
+ }
5188
+ const toast = document.createElement("div");
5189
+ toast.id = "cobuy-recovery-toast";
5190
+ toast.style.position = "fixed";
5191
+ toast.style.left = "50%";
5192
+ toast.style.bottom = "24px";
5193
+ toast.style.transform = "translateX(-50%)";
5194
+ toast.style.background = "#0f172a";
5195
+ toast.style.color = "#fff";
5196
+ toast.style.padding = "10px 14px";
5197
+ toast.style.borderRadius = "10px";
5198
+ toast.style.fontSize = "13px";
5199
+ toast.style.fontWeight = "600";
5200
+ toast.style.zIndex = "10040";
5201
+ toast.style.boxShadow = "0 8px 20px rgba(0,0,0,0.24)";
5202
+ toast.textContent = message;
5203
+ document.body.appendChild(toast);
5204
+ window.setTimeout(() => {
5205
+ toast.remove();
5206
+ }, 2800);
5207
+ }
4481
5208
  /** Subscribe once to backend socket events routed through the host page */
4482
5209
  subscribeToSocketEvents() {
4483
5210
  if (typeof window === "undefined" || this.socketListenerRegistered) {
@@ -4485,6 +5212,7 @@ var CoBuySDK = (function (exports) {
4485
5212
  }
4486
5213
  window.addEventListener("group:fulfilled", this.handleGroupFulfilledEvent);
4487
5214
  window.addEventListener("group:member:joined", this.handleGroupUpdatedEvent);
5215
+ window.addEventListener("group:member:left", this.handleGroupUpdatedEvent);
4488
5216
  window.addEventListener("group:created", this.handleGroupUpdatedEvent);
4489
5217
  this.socketListenerRegistered = true;
4490
5218
  }
@@ -4521,6 +5249,9 @@ var CoBuySDK = (function (exports) {
4521
5249
  isValidOfflineRedemption(groupData.offline_redemption)) {
4522
5250
  this.offlineRedemption = groupData.offline_redemption;
4523
5251
  }
5252
+ if (groupData.campaign_redemption_method) {
5253
+ this.campaignRedemptionMethod = groupData.campaign_redemption_method;
5254
+ }
4524
5255
  }
4525
5256
  }
4526
5257
  else {
@@ -4616,7 +5347,7 @@ var CoBuySDK = (function (exports) {
4616
5347
  }
4617
5348
  /** Persist fulfilled state, emit callback, and refresh UI */
4618
5349
  processGroupFulfilled(eventData) {
4619
- var _a, _b, _c, _d;
5350
+ var _a, _b, _c, _d, _e;
4620
5351
  this.groupFulfilled = true;
4621
5352
  // Extract reward from new event structure or fallback to legacy
4622
5353
  const reward = ((_a = eventData.frozen_reward) === null || _a === void 0 ? void 0 : _a.reward) || eventData.reward || null;
@@ -4631,7 +5362,10 @@ var CoBuySDK = (function (exports) {
4631
5362
  code: this.offlineRedemption.redemption_code,
4632
5363
  });
4633
5364
  }
4634
- (_d = (_c = this.events) === null || _c === void 0 ? void 0 : _c.onGroupFulfilled) === null || _d === void 0 ? void 0 : _d.call(_c, eventData);
5365
+ if ((_c = eventData.group) === null || _c === void 0 ? void 0 : _c.campaign_redemption_method) {
5366
+ this.campaignRedemptionMethod = eventData.group.campaign_redemption_method;
5367
+ }
5368
+ (_e = (_d = this.events) === null || _d === void 0 ? void 0 : _d.onGroupFulfilled) === null || _e === void 0 ? void 0 : _e.call(_d, eventData);
4635
5369
  this.renderFulfilledState();
4636
5370
  }
4637
5371
  /** Re-render widget and external containers to reflect fulfillment */
@@ -4771,8 +5505,10 @@ var CoBuySDK = (function (exports) {
4771
5505
  footer.style.justifyContent = "flex-end";
4772
5506
  footer.style.alignItems = "center";
4773
5507
  footer.style.gap = "12px";
4774
- // Add "Redeem In-store" CTA if offline redemption is available
4775
- if (this.offlineRedemption && isValidOfflineRedemption(this.offlineRedemption)) {
5508
+ // Add "Redeem In-store" CTA if offline redemption is available and campaign allows it
5509
+ if (this.offlineRedemption &&
5510
+ isValidOfflineRedemption(this.offlineRedemption) &&
5511
+ this.campaignRedemptionMethod !== "online") {
4776
5512
  const redeemLink = document.createElement("button");
4777
5513
  redeemLink.className = "cobuy-redeem-instore-link";
4778
5514
  redeemLink.style.background = "none";
@@ -4870,7 +5606,7 @@ var CoBuySDK = (function (exports) {
4870
5606
  }
4871
5607
  // Set callback to open lobby when a group is successfully joined
4872
5608
  this.groupListModal.setOnGroupJoined((joinData) => {
4873
- var _a;
5609
+ var _a, _b;
4874
5610
  // Update current group ID and session ID so the modal knows which group the user has joined
4875
5611
  this.currentGroupId = joinData.group.id;
4876
5612
  this.currentSessionId = ((_a = this.apiClient) === null || _a === void 0 ? void 0 : _a.getSessionId()) || null;
@@ -4884,8 +5620,9 @@ var CoBuySDK = (function (exports) {
4884
5620
  currentMembers: joinData.group.participants_count,
4885
5621
  totalMembers: joinData.group.max_participants,
4886
5622
  timeLeft: joinData.group.timeLeftSeconds,
5623
+ redemptionMethod: (_b = joinData.group.campaign_redemption_method) !== null && _b !== void 0 ? _b : this.campaignRedemptionMethod,
4887
5624
  };
4888
- const lobbyModal = new LobbyModal(lobbyData, {}, null, null, this.config.debug);
5625
+ const lobbyModal = new LobbyModal(lobbyData, {}, this.apiClient, null, this.analyticsClient, this.config.debug);
4889
5626
  lobbyModal.open(joinData.group.id);
4890
5627
  });
4891
5628
  // Set callback for viewing progress on already joined group
@@ -4901,8 +5638,9 @@ var CoBuySDK = (function (exports) {
4901
5638
  progress: Math.round((groupData.joined / groupData.total) * 100),
4902
5639
  currentMembers: groupData.joined,
4903
5640
  totalMembers: groupData.total,
5641
+ redemptionMethod: this.campaignRedemptionMethod,
4904
5642
  };
4905
- const lobbyModal = new LobbyModal(lobbyData, {}, null, null, this.config.debug);
5643
+ const lobbyModal = new LobbyModal(lobbyData, {}, this.apiClient, null, this.analyticsClient, this.config.debug);
4906
5644
  lobbyModal.open(groupId);
4907
5645
  });
4908
5646
  }
@@ -5086,6 +5824,9 @@ var CoBuySDK = (function (exports) {
5086
5824
  isValidOfflineRedemption(groupData.offline_redemption)) {
5087
5825
  this.offlineRedemption = groupData.offline_redemption;
5088
5826
  }
5827
+ if (groupData === null || groupData === void 0 ? void 0 : groupData.campaign_redemption_method) {
5828
+ this.campaignRedemptionMethod = groupData.campaign_redemption_method;
5829
+ }
5089
5830
  // Check if group is already fulfilled (full) on initial load
5090
5831
  if (groupData) {
5091
5832
  const participants = Number(groupData.participants_count || 0);
@@ -5807,10 +6548,99 @@ var CoBuySDK = (function (exports) {
5807
6548
  to { transform: rotate(360deg); }
5808
6549
  }
5809
6550
 
6551
+ .cobuy-prejoin-contact-overlay {
6552
+ position: fixed;
6553
+ inset: 0;
6554
+ z-index: 10045;
6555
+ background: rgba(2, 6, 23, 0.5);
6556
+ display: flex;
6557
+ align-items: center;
6558
+ justify-content: center;
6559
+ padding: 16px;
6560
+ }
6561
+
6562
+ .cobuy-prejoin-contact-card {
6563
+ width: min(440px, 100%);
6564
+ background: #fff;
6565
+ border-radius: 14px;
6566
+ padding: 18px;
6567
+ box-shadow: 0 14px 36px rgba(15, 23, 42, 0.22);
6568
+ display: flex;
6569
+ flex-direction: column;
6570
+ gap: 10px;
6571
+ }
6572
+
6573
+ .cobuy-prejoin-contact-title {
6574
+ font-size: 20px;
6575
+ font-weight: 800;
6576
+ color: #0f172a;
6577
+ margin: 0;
6578
+ }
6579
+
6580
+ .cobuy-prejoin-contact-subtitle {
6581
+ font-size: 14px;
6582
+ line-height: 1.5;
6583
+ color: #334155;
6584
+ margin: 0;
6585
+ }
6586
+
6587
+ .cobuy-prejoin-contact-input {
6588
+ width: 100%;
6589
+ border: 1px solid #cbd5e1;
6590
+ border-radius: 10px;
6591
+ padding: 11px 12px;
6592
+ font-size: 14px;
6593
+ outline: none;
6594
+ }
6595
+
6596
+ .cobuy-prejoin-contact-input:focus {
6597
+ border-color: #1d4ed8;
6598
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2);
6599
+ }
6600
+
6601
+ .cobuy-prejoin-contact-actions {
6602
+ display: flex;
6603
+ gap: 8px;
6604
+ flex-wrap: wrap;
6605
+ }
6606
+
6607
+ .cobuy-prejoin-contact-primary,
6608
+ .cobuy-prejoin-contact-secondary {
6609
+ border: none;
6610
+ border-radius: 10px;
6611
+ padding: 10px 12px;
6612
+ font-weight: 700;
6613
+ cursor: pointer;
6614
+ font-size: 13px;
6615
+ }
6616
+
6617
+ .cobuy-prejoin-contact-primary {
6618
+ background: #1d4ed8;
6619
+ color: #fff;
6620
+ }
6621
+
6622
+ .cobuy-prejoin-contact-primary:hover {
6623
+ background: #1e40af;
6624
+ }
6625
+
6626
+ .cobuy-prejoin-contact-secondary {
6627
+ background: #e2e8f0;
6628
+ color: #1e293b;
6629
+ }
6630
+
6631
+ .cobuy-prejoin-contact-secondary:hover {
6632
+ background: #cbd5e1;
6633
+ }
6634
+
5810
6635
  @media (max-width: 640px) {
5811
6636
  .cobuy-widget {
5812
6637
  grid-template-columns: 1fr;
5813
6638
  }
6639
+
6640
+ .cobuy-prejoin-contact-primary,
6641
+ .cobuy-prejoin-contact-secondary {
6642
+ width: 100%;
6643
+ }
5814
6644
  }
5815
6645
  `;
5816
6646
  document.head.appendChild(style);
@@ -5819,7 +6649,7 @@ var CoBuySDK = (function (exports) {
5819
6649
  * Handle CTA button click with analytics and modal opening
5820
6650
  */
5821
6651
  async handleCTAClick(productId) {
5822
- var _a, _b, _c, _d, _e, _f, _g;
6652
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
5823
6653
  this.logger.info(`CTA clicked for product: ${productId}`);
5824
6654
  // Track analytics event asynchronously (fire-and-forget)
5825
6655
  if (this.analyticsClient) {
@@ -5834,28 +6664,110 @@ var CoBuySDK = (function (exports) {
5834
6664
  // Join group before opening modal
5835
6665
  let groupJoinData = null;
5836
6666
  let inviteData = null;
6667
+ let recoveryGroupId = null;
5837
6668
  if (this.apiClient && this.currentGroupId) {
5838
6669
  try {
5839
- this.logger.info(`Joining group: ${this.currentGroupId}`);
5840
- if (this.analyticsClient) {
6670
+ recoveryGroupId = this.getStoredRecoveryGroupId(productId);
6671
+ if (this.analyticsClient && recoveryGroupId) {
5841
6672
  this.analyticsClient
5842
- .trackJoinAttempt(productId, this.currentGroupId)
6673
+ .trackEvent("RECOVERY_ATTEMPT", productId, {
6674
+ previousGroupId: recoveryGroupId,
6675
+ protectionState: "protected",
6676
+ })
5843
6677
  .catch((e) => this.logger.warn("Analytics tracking failed", e));
5844
6678
  }
5845
- const joinResponse = await this.apiClient.joinGroup(this.currentGroupId);
5846
- if (!joinResponse.success) {
5847
- this.logger.error("Failed to join group, modal will not open", joinResponse.error);
6679
+ const recoverResponse = await this.apiClient.recoverOrJoinGroup(productId);
6680
+ if (recoverResponse.success && recoverResponse.data) {
6681
+ groupJoinData = recoverResponse.data;
6682
+ this.currentGroupId = groupJoinData.group.id;
6683
+ this.clearStoredRecoveryGroupId(productId);
6684
+ if (this.analyticsClient && groupJoinData.recovery.recovered) {
6685
+ this.analyticsClient
6686
+ .trackEvent("RECOVERY_SUCCESS", productId, {
6687
+ previousGroupId: groupJoinData.recovery.previous_group_id || recoveryGroupId,
6688
+ joinedGroupId: groupJoinData.recovery.joined_group_id,
6689
+ recoveryOutcome: groupJoinData.recovery.outcome,
6690
+ protectionState: groupJoinData.recovery.matched_by === "none" ? "unprotected" : "protected",
6691
+ })
6692
+ .catch((e) => this.logger.warn("Analytics tracking failed", e));
6693
+ }
6694
+ else if (this.analyticsClient && recoveryGroupId) {
6695
+ this.analyticsClient
6696
+ .trackEvent("RECOVERY_FAILED", productId, {
6697
+ previousGroupId: recoveryGroupId,
6698
+ errorCode: "NOT_RECOVERED",
6699
+ errorMessage: "Recovery did not restore the previous membership.",
6700
+ protectionState: "protected",
6701
+ })
6702
+ .catch((e) => this.logger.warn("Analytics tracking failed", e));
6703
+ }
6704
+ switch (groupJoinData.recovery.outcome) {
6705
+ case "rejoined_previous_group":
6706
+ this.showRecoveryToast(RECOVERY_TOAST_REJOINED);
6707
+ break;
6708
+ case "joined_next_available_group":
6709
+ if (groupJoinData.recovery.recovered) {
6710
+ this.showRecoveryToast(RECOVERY_TOAST_NEXT_AVAILABLE);
6711
+ }
6712
+ break;
6713
+ case "created_new_group":
6714
+ if (groupJoinData.recovery.recovered) {
6715
+ this.showRecoveryToast(RECOVERY_TOAST_CREATED_NEW);
6716
+ }
6717
+ break;
6718
+ }
6719
+ }
6720
+ else {
6721
+ if (this.analyticsClient && recoveryGroupId) {
6722
+ const errCode = (_c = recoverResponse.error) === null || _c === void 0 ? void 0 : _c.code;
6723
+ const errMsg = (_d = recoverResponse.error) === null || _d === void 0 ? void 0 : _d.message;
6724
+ this.analyticsClient
6725
+ .trackEvent("RECOVERY_FAILED", productId, {
6726
+ previousGroupId: recoveryGroupId,
6727
+ errorCode: errCode || "RECOVERY_UNAVAILABLE",
6728
+ errorMessage: errMsg || "Recovery response was not successful.",
6729
+ protectionState: "protected",
6730
+ })
6731
+ .catch((e) => this.logger.warn("Analytics tracking failed", e));
6732
+ }
6733
+ const joinTargetGroupId = recoveryGroupId || this.currentGroupId;
6734
+ this.logger.info(`Joining group: ${joinTargetGroupId}`);
5848
6735
  if (this.analyticsClient) {
5849
- const errCode = (_c = joinResponse.error) === null || _c === void 0 ? void 0 : _c.code;
5850
- const errMsg = (_d = joinResponse.error) === null || _d === void 0 ? void 0 : _d.message;
5851
6736
  this.analyticsClient
5852
- .trackJoinFailure(productId, this.currentGroupId, errCode, errMsg)
6737
+ .trackJoinAttempt(productId, joinTargetGroupId)
5853
6738
  .catch((e) => this.logger.warn("Analytics tracking failed", e));
5854
6739
  }
5855
- this.setButtonLoadingState(false);
5856
- return; // Don't open modal on error
6740
+ let joinResponse = await this.apiClient.joinGroup(joinTargetGroupId);
6741
+ if (!joinResponse.success && recoveryGroupId && this.currentGroupId !== recoveryGroupId) {
6742
+ this.clearStoredRecoveryGroupId(productId);
6743
+ joinResponse = await this.apiClient.joinGroup(this.currentGroupId);
6744
+ }
6745
+ if (!joinResponse.success) {
6746
+ this.logger.error("Failed to join group, modal will not open", joinResponse.error);
6747
+ if (this.analyticsClient) {
6748
+ const errCode = (_e = joinResponse.error) === null || _e === void 0 ? void 0 : _e.code;
6749
+ const errMsg = (_f = joinResponse.error) === null || _f === void 0 ? void 0 : _f.message;
6750
+ this.analyticsClient
6751
+ .trackJoinFailure(productId, joinTargetGroupId, errCode, errMsg)
6752
+ .catch((e) => this.logger.warn("Analytics tracking failed", e));
6753
+ }
6754
+ this.setButtonLoadingState(false);
6755
+ return; // Don't open modal on error
6756
+ }
6757
+ groupJoinData = joinResponse.data;
6758
+ if ((_g = groupJoinData === null || groupJoinData === void 0 ? void 0 : groupJoinData.group) === null || _g === void 0 ? void 0 : _g.id) {
6759
+ this.currentGroupId = groupJoinData.group.id;
6760
+ }
6761
+ if (recoveryGroupId && ((_h = groupJoinData === null || groupJoinData === void 0 ? void 0 : groupJoinData.group) === null || _h === void 0 ? void 0 : _h.id)) {
6762
+ this.clearStoredRecoveryGroupId(productId);
6763
+ if (groupJoinData.group.id !== recoveryGroupId) {
6764
+ this.showRecoveryToast(RECOVERY_TOAST_NEXT_AVAILABLE);
6765
+ }
6766
+ else {
6767
+ this.showRecoveryToast(RECOVERY_TOAST_REJOINED);
6768
+ }
6769
+ }
5857
6770
  }
5858
- groupJoinData = joinResponse.data;
5859
6771
  this.logger.info("Successfully joined group", groupJoinData);
5860
6772
  if (this.analyticsClient && groupJoinData) {
5861
6773
  this.analyticsClient
@@ -5868,26 +6780,39 @@ var CoBuySDK = (function (exports) {
5868
6780
  isValidOfflineRedemption(groupJoinData.offline_redemption)
5869
6781
  ? groupJoinData.offline_redemption
5870
6782
  : null;
6783
+ const joinedGroupId = (_j = groupJoinData === null || groupJoinData === void 0 ? void 0 : groupJoinData.group) === null || _j === void 0 ? void 0 : _j.id;
5871
6784
  // Trigger invite tracking before opening lobby (global for product)
5872
- try {
5873
- const inviteResponse = await this.apiClient.inviteToGroup(this.currentGroupId, "copy_link");
5874
- if (inviteResponse.success && inviteResponse.data) {
5875
- inviteData = inviteResponse.data;
5876
- this.logger.info("Invite link generated", inviteData);
6785
+ if (joinedGroupId) {
6786
+ try {
6787
+ const inviteResponse = await this.apiClient.inviteToGroup(joinedGroupId, "copy_link");
6788
+ if (inviteResponse.success && inviteResponse.data) {
6789
+ inviteData = inviteResponse.data;
6790
+ this.logger.info("Invite link generated", inviteData);
6791
+ }
6792
+ else {
6793
+ this.logger.warn("Invite link generation failed", inviteResponse.error);
6794
+ }
5877
6795
  }
5878
- else {
5879
- this.logger.warn("Invite link generation failed", inviteResponse.error);
6796
+ catch (inviteError) {
6797
+ this.logger.warn("Invite request failed", inviteError);
5880
6798
  }
5881
6799
  }
5882
- catch (inviteError) {
5883
- this.logger.warn("Invite request failed", inviteError);
5884
- }
5885
6800
  }
5886
6801
  catch (error) {
5887
6802
  this.logger.error("Group join failed, modal will not open", error);
6803
+ if (this.analyticsClient && recoveryGroupId) {
6804
+ this.analyticsClient
6805
+ .trackEvent("RECOVERY_FAILED", productId, {
6806
+ previousGroupId: recoveryGroupId,
6807
+ errorCode: "EXCEPTION",
6808
+ errorMessage: error instanceof Error ? error.message : String(error),
6809
+ protectionState: "protected",
6810
+ })
6811
+ .catch((e) => this.logger.warn("Analytics tracking failed", e));
6812
+ }
5888
6813
  if (this.analyticsClient) {
5889
6814
  this.analyticsClient
5890
- .trackJoinFailure(productId, (_e = this.currentGroupId) !== null && _e !== void 0 ? _e : undefined, "EXCEPTION", error instanceof Error ? error.message : String(error))
6815
+ .trackJoinFailure(productId, (_k = this.currentGroupId) !== null && _k !== void 0 ? _k : undefined, "EXCEPTION", error instanceof Error ? error.message : String(error))
5891
6816
  .catch((e) => this.logger.warn("Analytics tracking failed", e));
5892
6817
  }
5893
6818
  this.setButtonLoadingState(false);
@@ -5904,7 +6829,7 @@ var CoBuySDK = (function (exports) {
5904
6829
  const progress = Math.round((groupJoinData.group.participants_count / groupJoinData.group.max_participants) * 100);
5905
6830
  // Format discount based on reward type
5906
6831
  let discountText = "";
5907
- if ((_g = (_f = this.currentRewardData) === null || _f === void 0 ? void 0 : _f.reward) === null || _g === void 0 ? void 0 : _g.value) {
6832
+ if ((_m = (_l = this.currentRewardData) === null || _l === void 0 ? void 0 : _l.reward) === null || _m === void 0 ? void 0 : _m.value) {
5908
6833
  const rewardType = this.currentRewardData.reward.type;
5909
6834
  const rewardValue = this.currentRewardData.reward.value;
5910
6835
  if (rewardType === "percentage" || rewardType === "cashback") {
@@ -5944,6 +6869,7 @@ var CoBuySDK = (function (exports) {
5944
6869
  shareMessage: shareMessageFromInvite,
5945
6870
  isLocked: !isGroupFulfilled,
5946
6871
  offlineRedemption: offlineRedemptionFromJoin,
6872
+ redemptionMethod: (_o = groupJoinData.group.campaign_redemption_method) !== null && _o !== void 0 ? _o : this.campaignRedemptionMethod,
5947
6873
  onShare: this.analyticsClient
5948
6874
  ? () => {
5949
6875
  this.analyticsClient.trackShareClick(productId, groupJoinData.group.id, "other").catch((e) => this.logger.warn("Analytics tracking failed", e));
@@ -6114,8 +7040,10 @@ var CoBuySDK = (function (exports) {
6114
7040
  PRODUCT_CONTEXT: "/v1/sdk/products/:productId/context",
6115
7041
  PRODUCT_REWARD: "/v1/sdk/products/:productId/reward",
6116
7042
  PRODUCT_PRIMARY_GROUP: "/v1/sdk/products/:productId/group/primary",
7043
+ PRODUCT_RECOVER_OR_JOIN_GROUP: "/v1/sdk/products/:productId/group/recover-or-join",
6117
7044
  // Group endpoints
6118
7045
  GROUP_JOIN: "/v1/sdk/groups/:groupId/join",
7046
+ GROUP_LEAVE: "/v1/sdk/groups/:groupId/leave",
6119
7047
  GROUP_CREATE_AND_JOIN: "/v1/sdk/groups/new/join",
6120
7048
  PRODUCT_ACTIVE_GROUPS: "/v1/sdk/products/:productId/groups/active",
6121
7049
  GROUP_INVITE: "/v1/sdk/groups/:groupId/invite",
@@ -7206,6 +8134,75 @@ var CoBuySDK = (function (exports) {
7206
8134
  },
7207
8135
  };
7208
8136
  }
8137
+ /**
8138
+ * Leave an active group for the current SDK session.
8139
+ */
8140
+ async leaveGroup(groupId, params) {
8141
+ const endpoint = buildApiUrl("", API_ENDPOINTS.GROUP_LEAVE, { groupId });
8142
+ this.logger.info(`Leaving group: ${groupId}`);
8143
+ const response = await this.post(endpoint, {
8144
+ leave_source: (params === null || params === void 0 ? void 0 : params.leave_source) || "unknown",
8145
+ leave_reason: (params === null || params === void 0 ? void 0 : params.leave_reason) || "unknown",
8146
+ });
8147
+ if (response.success) {
8148
+ const payload = response.data;
8149
+ return {
8150
+ success: true,
8151
+ data: ((payload === null || payload === void 0 ? void 0 : payload.data) || response.data),
8152
+ };
8153
+ }
8154
+ return {
8155
+ success: false,
8156
+ error: response.error || {
8157
+ message: "Failed to leave group",
8158
+ code: "LEAVE_GROUP_ERROR",
8159
+ },
8160
+ };
8161
+ }
8162
+ async recoverOrJoinGroup(productId, contact) {
8163
+ var _a;
8164
+ const endpoint = buildApiUrl("", API_ENDPOINTS.PRODUCT_RECOVER_OR_JOIN_GROUP, {
8165
+ productId,
8166
+ });
8167
+ this.logger.info(`Recovering or joining group for product: ${productId}`);
8168
+ const response = await this.post(endpoint, contact ? { contact } : {});
8169
+ if (response.success && ((_a = response.data) === null || _a === void 0 ? void 0 : _a.data)) {
8170
+ return {
8171
+ success: true,
8172
+ data: response.data.data,
8173
+ };
8174
+ }
8175
+ return {
8176
+ success: false,
8177
+ error: response.error || {
8178
+ message: "Failed to recover or join group",
8179
+ code: "RECOVER_OR_JOIN_GROUP_ERROR",
8180
+ },
8181
+ };
8182
+ }
8183
+ /**
8184
+ * Best-effort leave signal for unload/pagehide scenarios.
8185
+ * Uses fetch keepalive so it can run while page is closing.
8186
+ */
8187
+ leaveGroupBestEffort(groupId, params) {
8188
+ if (!groupId)
8189
+ return;
8190
+ const endpoint = buildApiUrl("", API_ENDPOINTS.GROUP_LEAVE, { groupId });
8191
+ const url = `${this.baseUrl}${endpoint}`;
8192
+ const payload = JSON.stringify({
8193
+ leave_source: (params === null || params === void 0 ? void 0 : params.leave_source) || "browser_close",
8194
+ leave_reason: (params === null || params === void 0 ? void 0 : params.leave_reason) || "voluntary_no_contact",
8195
+ });
8196
+ const authHeaders = this.authStrategy.getHeaders();
8197
+ void fetch(url, {
8198
+ method: "POST",
8199
+ headers: Object.assign({ "Content-Type": "application/json", "X-CoBuy-SDK-Version": "1.0.0", "X-CoBuy-Session": this.sessionId }, authHeaders),
8200
+ body: payload,
8201
+ keepalive: true,
8202
+ }).catch((error) => {
8203
+ this.logger.debug("Best-effort leave request failed", error);
8204
+ });
8205
+ }
7209
8206
  /**
7210
8207
  * Prepare checkout for a group
7211
8208
  *
@@ -12035,15 +13032,16 @@ var CoBuySDK = (function (exports) {
12035
13032
  return;
12036
13033
  const bind = (eventName, handler) => {
12037
13034
  var _a;
12038
- if (!handler)
12039
- return;
12040
13035
  (_a = this.socket) === null || _a === void 0 ? void 0 : _a.on(eventName, (payload) => {
12041
13036
  this.logger.info(`[Socket] ${eventName} payload: ${this.formatPayload(payload)}`);
12042
13037
  this.dispatchWindowEvent(eventName, payload);
12043
- handler(payload);
13038
+ if (handler) {
13039
+ handler(payload);
13040
+ }
12044
13041
  });
12045
13042
  };
12046
13043
  bind("group:member:joined", handlers.onGroupMemberJoined);
13044
+ bind("group:member:left", handlers.onGroupMemberLeft);
12047
13045
  bind("group:created", handlers.onGroupCreated);
12048
13046
  bind("group:fulfilled", handlers.onGroupFulfilled);
12049
13047
  }
@@ -12054,6 +13052,7 @@ var CoBuySDK = (function (exports) {
12054
13052
  if (!this.socket)
12055
13053
  return;
12056
13054
  this.socket.off("group:member:joined");
13055
+ this.socket.off("group:member:left");
12057
13056
  this.socket.off("group:created");
12058
13057
  this.socket.off("group:fulfilled");
12059
13058
  }
@@ -13427,6 +14426,7 @@ var CoBuySDK = (function (exports) {
13427
14426
  activities: options.activities,
13428
14427
  isLocked: options.isLocked,
13429
14428
  offlineRedemption: options.offlineRedemption,
14429
+ redemptionMethod: options.redemptionMethod,
13430
14430
  };
13431
14431
  // Create modal instance
13432
14432
  const modal = new LobbyModal(modalData, {
@@ -13441,7 +14441,7 @@ var CoBuySDK = (function (exports) {
13441
14441
  },
13442
14442
  onCopyLink: options.onCopyLink,
13443
14443
  onShare: options.onShare,
13444
- }, this.apiClient, this.socketManager, config.debug);
14444
+ }, this.apiClient, this.socketManager, this.analyticsClient, config.debug);
13445
14445
  // Store in map for persistence
13446
14446
  this.modals.set(modalKey, modal);
13447
14447
  // Maintain backward compatibility