@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.
- package/dist/cobuy-sdk.esm.js +1057 -57
- package/dist/cobuy-sdk.esm.js.map +1 -1
- package/dist/cobuy-sdk.umd.js +1057 -57
- package/dist/cobuy-sdk.umd.js.map +1 -1
- package/dist/types/core/api-client.d.ts +17 -1
- package/dist/types/core/endpoints.d.ts +2 -0
- package/dist/types/core/socket.d.ts +3 -2
- package/dist/types/core/types.d.ts +39 -0
- package/dist/types/ui/lobby/lobby-modal.d.ts +49 -2
- package/dist/types/ui/widget/widget-root.d.ts +6 -0
- package/package.json +1 -1
package/dist/cobuy-sdk.umd.js
CHANGED
|
@@ -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
|
-
|
|
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(
|
|
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.
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
|
|
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 &&
|
|
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
|
-
//
|
|
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
|
-
//
|
|
3857
|
-
if (
|
|
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
|
-
|
|
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 &&
|
|
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, {},
|
|
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, {},
|
|
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
|
-
|
|
5840
|
-
if (this.analyticsClient) {
|
|
6670
|
+
recoveryGroupId = this.getStoredRecoveryGroupId(productId);
|
|
6671
|
+
if (this.analyticsClient && recoveryGroupId) {
|
|
5841
6672
|
this.analyticsClient
|
|
5842
|
-
.
|
|
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
|
|
5846
|
-
if (
|
|
5847
|
-
|
|
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
|
-
.
|
|
6737
|
+
.trackJoinAttempt(productId, joinTargetGroupId)
|
|
5853
6738
|
.catch((e) => this.logger.warn("Analytics tracking failed", e));
|
|
5854
6739
|
}
|
|
5855
|
-
this.
|
|
5856
|
-
|
|
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
|
-
|
|
5873
|
-
|
|
5874
|
-
|
|
5875
|
-
|
|
5876
|
-
|
|
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
|
-
|
|
5879
|
-
this.logger.warn("Invite
|
|
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, (
|
|
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 ((
|
|
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
|
|
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
|