@cshah18/sdk 4.2.0 → 4.3.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.
@@ -1852,9 +1852,12 @@ class LobbyModal {
1852
1852
  // Top section
1853
1853
  const topSection = this.createTopSection();
1854
1854
  mainContent.appendChild(topSection);
1855
- // Activity section
1856
- const activitySection = this.createActivitySection();
1857
- mainContent.appendChild(activitySection);
1855
+ // Activity section (hidden when offline redemption is present to keep layout compact)
1856
+ const hasOfflineRedemption = this.data.offlineRedemption && isValidOfflineRedemption(this.data.offlineRedemption);
1857
+ if (!hasOfflineRedemption) {
1858
+ const activitySection = this.createActivitySection();
1859
+ mainContent.appendChild(activitySection);
1860
+ }
1858
1861
  mainWrapper.appendChild(mainContent);
1859
1862
  modal.appendChild(background);
1860
1863
  modal.appendChild(mainWrapper);
@@ -1971,10 +1974,11 @@ class LobbyModal {
1971
1974
  connectedSection.appendChild(subtitle);
1972
1975
  // Check if group is fulfilled and has offline redemption
1973
1976
  const isComplete = !this.computeIsLocked(this.data);
1974
- if (isComplete &&
1977
+ const hasOfflineRedemption = isComplete &&
1975
1978
  this.data.offlineRedemption &&
1976
- isValidOfflineRedemption(this.data.offlineRedemption)) {
1977
- // Show offline redemption view instead of link/share
1979
+ isValidOfflineRedemption(this.data.offlineRedemption);
1980
+ if (hasOfflineRedemption) {
1981
+ // Show offline redemption view with integrated actions
1978
1982
  const offlineSection = this.createOfflineRedemptionSection(this.data.offlineRedemption);
1979
1983
  connectedSection.appendChild(offlineSection);
1980
1984
  }
@@ -2030,6 +2034,9 @@ class LobbyModal {
2030
2034
  const section = document.createElement("div");
2031
2035
  section.className = "offline-redemption-section";
2032
2036
  section.id = "lobbyOfflineRedemptionSection";
2037
+ // Top row: QR + Code side by side
2038
+ const topRow = document.createElement("div");
2039
+ topRow.className = "offline-top-row";
2033
2040
  // QR Code container
2034
2041
  const qrContainer = document.createElement("div");
2035
2042
  qrContainer.className = "offline-qr-container";
@@ -2059,29 +2066,40 @@ class LobbyModal {
2059
2066
  copyCodeBtn.className = "offline-copy-code-btn";
2060
2067
  copyCodeBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg>`;
2061
2068
  copyCodeBtn.addEventListener("click", () => this.copyOfflineRedemptionCode(offlineRedemption.redemption_code, copyCodeBtn));
2069
+ const codeRow = document.createElement("div");
2070
+ codeRow.className = "offline-code-row";
2071
+ codeRow.appendChild(codeValue);
2072
+ codeRow.appendChild(copyCodeBtn);
2062
2073
  codeBox.appendChild(codeLabel);
2063
- codeBox.appendChild(codeValue);
2064
- codeBox.appendChild(copyCodeBtn);
2065
- // Expiry info
2074
+ codeBox.appendChild(codeRow);
2075
+ topRow.appendChild(qrContainer);
2076
+ topRow.appendChild(codeBox);
2077
+ // Expiry info - compact single line
2066
2078
  const expiryInfo = document.createElement("div");
2067
2079
  expiryInfo.className = "offline-expiry-info";
2068
- const expiryLabel = document.createElement("p");
2069
- expiryLabel.className = "offline-expiry-label";
2070
- expiryLabel.textContent = "Valid Until";
2071
- const expiryValue = document.createElement("p");
2072
- expiryValue.className = "offline-expiry-value";
2073
- expiryValue.textContent = formatExpiryDate(offlineRedemption.offline_expires_at);
2074
- expiryInfo.appendChild(expiryLabel);
2075
- expiryInfo.appendChild(expiryValue);
2080
+ expiryInfo.innerHTML = `<span class="offline-expiry-label">Valid Until:</span> <span class="offline-expiry-value">${formatExpiryDate(offlineRedemption.offline_expires_at)}</span>`;
2081
+ // Action buttons row
2082
+ const actionsRow = document.createElement("div");
2083
+ actionsRow.className = "offline-actions-row";
2076
2084
  // Download QR button
2077
2085
  const downloadQRBtn = document.createElement("button");
2078
2086
  downloadQRBtn.className = "offline-download-qr-btn";
2079
2087
  downloadQRBtn.textContent = "Download QR";
2080
2088
  downloadQRBtn.addEventListener("click", () => this.downloadOfflineQR(offlineRedemption, downloadQRBtn));
2081
- section.appendChild(qrContainer);
2082
- section.appendChild(codeBox);
2089
+ // Online checkout button
2090
+ const onlineCheckoutBtn = document.createElement("button");
2091
+ onlineCheckoutBtn.className = "offline-online-checkout-btn";
2092
+ onlineCheckoutBtn.textContent = "Checkout Online";
2093
+ onlineCheckoutBtn.addEventListener("click", () => {
2094
+ if (this.data.groupLink) {
2095
+ window.open(this.data.groupLink, "_blank");
2096
+ }
2097
+ });
2098
+ actionsRow.appendChild(downloadQRBtn);
2099
+ actionsRow.appendChild(onlineCheckoutBtn);
2100
+ section.appendChild(topRow);
2083
2101
  section.appendChild(expiryInfo);
2084
- section.appendChild(downloadQRBtn);
2102
+ section.appendChild(actionsRow);
2085
2103
  // Inject styles for offline redemption section
2086
2104
  this.injectOfflineRedemptionStyles();
2087
2105
  return section;
@@ -2126,117 +2144,185 @@ class LobbyModal {
2126
2144
  .offline-redemption-section {
2127
2145
  display: flex;
2128
2146
  flex-direction: column;
2129
- gap: 16px;
2130
- padding: 16px 0;
2147
+ gap: 14px;
2148
+ padding: 16px;
2149
+ background: linear-gradient(135deg, #f9fafb 0%, #f3f4f6 100%);
2150
+ border: 1.5px solid #e5e7eb;
2151
+ border-radius: 12px;
2152
+ margin-top: 12px;
2153
+ }
2154
+
2155
+ .offline-top-row {
2156
+ display: flex;
2157
+ gap: 14px;
2158
+ align-items: stretch;
2131
2159
  }
2132
2160
 
2133
2161
  .offline-qr-container {
2162
+ flex: 0 0 120px;
2134
2163
  display: flex;
2135
2164
  justify-content: center;
2136
- background: #f9fafb;
2137
- padding: 12px;
2138
- border-radius: 8px;
2139
- min-height: 160px;
2140
2165
  align-items: center;
2166
+ background: white;
2167
+ padding: 10px;
2168
+ border-radius: 8px;
2169
+ border: 1.5px solid #e5e7eb;
2170
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.04);
2141
2171
  }
2142
2172
 
2143
2173
  .offline-qr-image {
2144
- max-width: 140px;
2145
- max-height: 140px;
2174
+ max-width: 100px;
2175
+ max-height: 100px;
2146
2176
  width: auto;
2147
2177
  height: auto;
2178
+ filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.08));
2148
2179
  }
2149
2180
 
2150
2181
  .offline-qr-fallback {
2151
2182
  color: #9ca3af;
2152
- font-size: 12px;
2183
+ font-size: 11px;
2153
2184
  text-align: center;
2154
2185
  }
2155
2186
 
2156
2187
  .offline-code-box {
2188
+ flex: 1;
2157
2189
  display: flex;
2158
2190
  flex-direction: column;
2159
- gap: 6px;
2191
+ gap: 8px;
2192
+ justify-content: center;
2193
+ }
2194
+
2195
+ .offline-code-row {
2196
+ position: relative;
2197
+ display: flex;
2198
+ align-items: center;
2160
2199
  }
2161
2200
 
2162
2201
  .offline-code-label {
2163
2202
  margin: 0;
2164
2203
  font-size: 11px;
2165
- font-weight: 600;
2166
- color: #6b7280;
2204
+ font-weight: 700;
2205
+ color: #1f2937;
2167
2206
  text-transform: uppercase;
2168
2207
  letter-spacing: 0.5px;
2169
2208
  }
2170
2209
 
2171
2210
  .offline-code-value {
2172
- font-family: monospace;
2211
+ font-family: 'Courier New', monospace;
2173
2212
  font-size: 14px;
2174
- font-weight: 600;
2213
+ font-weight: 700;
2175
2214
  color: #111827;
2176
- padding: 10px 12px;
2177
- background: #f9fafb;
2178
- border: 1px solid #e5e7eb;
2179
- border-radius: 6px;
2215
+ padding: 10px 40px 10px 12px;
2216
+ background: white;
2217
+ border: 1.5px solid #d1d5db;
2218
+ border-radius: 8px;
2180
2219
  text-align: center;
2181
- letter-spacing: 1px;
2220
+ letter-spacing: 1.5px;
2182
2221
  position: relative;
2183
2222
  display: flex;
2184
2223
  align-items: center;
2185
2224
  justify-content: center;
2225
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
2226
+ transition: all 0.2s;
2227
+ word-break: break-all;
2228
+ }
2229
+
2230
+ .offline-code-row .offline-code-value {
2231
+ width: 100%;
2232
+ }
2233
+
2234
+ .offline-code-value:hover {
2235
+ border-color: #3b82f6;
2236
+ box-shadow: 0 2px 6px rgba(59, 130, 246, 0.1);
2186
2237
  }
2187
2238
 
2188
2239
  .offline-copy-code-btn {
2189
2240
  position: absolute;
2190
- right: 8px;
2241
+ right: 6px;
2242
+ top: 50%;
2243
+ transform: translateY(-50%);
2191
2244
  background: none;
2192
2245
  border: none;
2193
- padding: 4px 8px;
2246
+ padding: 5px 8px;
2194
2247
  cursor: pointer;
2195
2248
  color: #6b7280;
2196
2249
  display: flex;
2197
2250
  align-items: center;
2198
- transition: color 0.2s;
2251
+ justify-content: center;
2252
+ transition: all 0.2s;
2253
+ border-radius: 4px;
2199
2254
  }
2200
2255
 
2201
2256
  .offline-copy-code-btn:hover {
2202
- color: #111827;
2257
+ color: #3b82f6;
2258
+ background: #eff6ff;
2203
2259
  }
2204
2260
 
2205
2261
  .offline-expiry-info {
2206
- display: flex;
2207
- flex-direction: column;
2208
- gap: 4px;
2262
+ font-size: 11px;
2263
+ color: #6b7280;
2264
+ text-align: center;
2265
+ padding: 6px 0;
2209
2266
  }
2210
2267
 
2211
2268
  .offline-expiry-label {
2212
- margin: 0;
2213
- font-size: 11px;
2214
- font-weight: 600;
2215
- color: #6b7280;
2269
+ font-weight: 700;
2216
2270
  text-transform: uppercase;
2217
2271
  letter-spacing: 0.5px;
2272
+ color: #1f2937;
2218
2273
  }
2219
2274
 
2220
2275
  .offline-expiry-value {
2221
- margin: 0;
2222
- font-size: 13px;
2276
+ font-weight: 600;
2223
2277
  color: #374151;
2224
2278
  }
2225
2279
 
2226
- .offline-download-qr-btn {
2227
- padding: 10px 16px;
2228
- background: #3b82f6;
2229
- color: white;
2280
+ .offline-actions-row {
2281
+ display: flex;
2282
+ gap: 10px;
2283
+ }
2284
+
2285
+ .offline-download-qr-btn,
2286
+ .offline-online-checkout-btn {
2287
+ flex: 1;
2288
+ padding: 11px 16px;
2230
2289
  border: none;
2231
- border-radius: 6px;
2290
+ border-radius: 8px;
2232
2291
  font-size: 13px;
2233
- font-weight: 600;
2292
+ font-weight: 700;
2234
2293
  cursor: pointer;
2235
- transition: background 0.2s;
2294
+ transition: all 0.2s;
2295
+ text-transform: uppercase;
2296
+ letter-spacing: 0.4px;
2297
+ }
2298
+
2299
+ .offline-download-qr-btn {
2300
+ background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
2301
+ color: white;
2302
+ box-shadow: 0 2px 6px rgba(59, 130, 246, 0.2);
2236
2303
  }
2237
2304
 
2238
2305
  .offline-download-qr-btn:hover:not(:disabled) {
2239
- background: #2563eb;
2306
+ background: linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%);
2307
+ box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
2308
+ transform: translateY(-1px);
2309
+ }
2310
+
2311
+ .offline-online-checkout-btn {
2312
+ background: linear-gradient(135deg, #111827 0%, #1f2937 100%);
2313
+ color: white;
2314
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
2315
+ }
2316
+
2317
+ .offline-online-checkout-btn:hover {
2318
+ background: linear-gradient(135deg, #1f2937 0%, #374151 100%);
2319
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
2320
+ transform: translateY(-1px);
2321
+ }
2322
+
2323
+ .offline-download-qr-btn:active:not(:disabled),
2324
+ .offline-online-checkout-btn:active {
2325
+ transform: translateY(0);
2240
2326
  }
2241
2327
 
2242
2328
  .offline-download-qr-btn:disabled {