@codebards/ik-embeddable-form 0.0.2733668477-qa → 0.0.2736696173-qa

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/embed.js CHANGED
@@ -1574,41 +1574,143 @@ var IKEmbeddableFormBundle = function(exports) {
1574
1574
  "December"
1575
1575
  ];
1576
1576
  const WEEKDAYS = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
1577
- function createFutureStaticSlots(count = 3) {
1578
- const pad = (n2) => String(n2).padStart(2, "0");
1579
- const slots = [];
1577
+ const FALLBACK_SCHEDULES = {
1578
+ IND: {
1579
+ skipDay: null,
1580
+ timeSlots: {
1581
+ 0: "12:00:00",
1582
+ 1: "18:00:00",
1583
+ 2: "18:00:00",
1584
+ 3: "18:00:00",
1585
+ 4: "18:00:00",
1586
+ 5: "18:00:00",
1587
+ 6: "12:00:00"
1588
+ },
1589
+ timeZone: "Asia/Kolkata",
1590
+ utcOffsetHours: 5.5
1591
+ },
1592
+ USA: {
1593
+ skipDay: 6,
1594
+ timeSlots: {
1595
+ 0: "20:30:00",
1596
+ 1: "19:30:00",
1597
+ 2: "20:30:00",
1598
+ 3: "19:30:00",
1599
+ 4: "20:30:00",
1600
+ 5: "19:30:00",
1601
+ 6: null
1602
+ },
1603
+ timeZone: "America/New_York",
1604
+ utcOffsetHours: -5
1605
+ }
1606
+ };
1607
+ function pad2(n2) {
1608
+ return String(n2).padStart(2, "0");
1609
+ }
1610
+ function formatUtcOffset(offsetHours) {
1611
+ const sign = offsetHours >= 0 ? "+" : "-";
1612
+ const abs = Math.abs(offsetHours);
1613
+ const hours = Math.floor(abs);
1614
+ const minutes = Math.round((abs - hours) * 60);
1615
+ return `${sign}${pad2(hours)}:${pad2(minutes)}`;
1616
+ }
1617
+ function todayInTimeZone(timeZone) {
1618
+ const parts = new Intl.DateTimeFormat("en-US", {
1619
+ timeZone,
1620
+ year: "numeric",
1621
+ month: "2-digit",
1622
+ day: "2-digit"
1623
+ }).formatToParts(/* @__PURE__ */ new Date());
1624
+ const get2 = (type) => {
1625
+ var _a;
1626
+ return Number((_a = parts.find((p2) => p2.type === type)) == null ? void 0 : _a.value);
1627
+ };
1628
+ return { year: get2("year"), month: get2("month"), day: get2("day") };
1629
+ }
1630
+ function wallClockParts(date, timeZone) {
1631
+ const parts = new Intl.DateTimeFormat("en-US", {
1632
+ timeZone,
1633
+ year: "numeric",
1634
+ month: "2-digit",
1635
+ day: "2-digit",
1636
+ hour: "2-digit",
1637
+ minute: "2-digit",
1638
+ second: "2-digit",
1639
+ hourCycle: "h23"
1640
+ }).formatToParts(date);
1641
+ const get2 = (type) => {
1642
+ var _a;
1643
+ return Number((_a = parts.find((p2) => p2.type === type)) == null ? void 0 : _a.value);
1644
+ };
1645
+ return {
1646
+ year: get2("year"),
1647
+ month: get2("month"),
1648
+ day: get2("day"),
1649
+ hour: get2("hour"),
1650
+ minute: get2("minute"),
1651
+ second: get2("second")
1652
+ };
1653
+ }
1654
+ function timeZoneOffsetString(timeZone, at) {
1655
+ var _a;
1656
+ try {
1657
+ const raw = ((_a = new Intl.DateTimeFormat("en-US", { timeZone, timeZoneName: "longOffset" }).formatToParts(at).find((p2) => p2.type === "timeZoneName")) == null ? void 0 : _a.value) ?? "GMT+00:00";
1658
+ let offset = raw.replace("GMT", "") || "+00:00";
1659
+ if (/^[+-]\d:/.test(offset)) offset = offset.replace(/^([+-])(\d):/, "$10$2:");
1660
+ return offset || "+00:00";
1661
+ } catch {
1662
+ return "+00:00";
1663
+ }
1664
+ }
1665
+ function generateFallbackSlots(country, targetTimezone, webinarType, count = 13) {
1666
+ const schedule = FALLBACK_SCHEDULES[country === "IND" ? "IND" : "USA"];
1667
+ const scheduleOffset = formatUtcOffset(schedule.utcOffsetHours);
1668
+ const today = todayInTimeZone(schedule.timeZone);
1580
1669
  const now = /* @__PURE__ */ new Date();
1670
+ const slots = [];
1581
1671
  for (let i2 = 0; i2 < count; i2++) {
1582
- const start = new Date(now);
1583
- start.setDate(start.getDate() + 7 * (i2 + 1));
1584
- start.setHours(19, 30, 0, 0);
1585
- const end = new Date(start);
1586
- end.setHours(20, 30, 0, 0);
1587
- const hour12 = start.getHours() % 12 || 12;
1588
- const ampm = start.getHours() >= 12 ? "PM" : "AM";
1589
- const offsetMin = -start.getTimezoneOffset();
1590
- const sign = offsetMin >= 0 ? "+" : "-";
1591
- const tzOffset = `${sign}${pad(Math.floor(Math.abs(offsetMin) / 60))}:${pad(Math.abs(offsetMin) % 60)}`;
1592
- const toIso = (d2) => `${d2.getFullYear()}-${pad(d2.getMonth() + 1)}-${pad(d2.getDate())}T${pad(d2.getHours())}:${pad(d2.getMinutes())}:00${tzOffset}`;
1593
- const weekday = WEEKDAYS[start.getDay()] ?? "Tuesday";
1594
- const monthLabel = MONTHS[start.getMonth()] ?? "June";
1595
- const day = pad(start.getDate());
1596
- const year = String(start.getFullYear());
1597
- const minute = pad(start.getMinutes());
1598
- const endHour12 = end.getHours() % 12 || 12;
1599
- const endAmpm = end.getHours() >= 12 ? "PM" : "AM";
1672
+ const candidate = new Date(today.year, today.month - 1, today.day);
1673
+ candidate.setDate(candidate.getDate() + i2);
1674
+ const weekday = candidate.getDay();
1675
+ if (weekday === schedule.skipDay) continue;
1676
+ const time = schedule.timeSlots[weekday];
1677
+ if (!time) continue;
1678
+ const [hour, minute, second] = time.split(":").map(Number);
1679
+ candidate.setHours(hour, minute, second, 0);
1680
+ const isoInSchedule = `${candidate.getFullYear()}-${pad2(candidate.getMonth() + 1)}-${pad2(candidate.getDate())}T${pad2(candidate.getHours())}:${pad2(candidate.getMinutes())}:${pad2(candidate.getSeconds())}${scheduleOffset}`;
1681
+ const instant = new Date(isoInSchedule);
1682
+ if (Number.isNaN(instant.getTime()) || instant < now) continue;
1683
+ const end = new Date(instant.getTime() + 60 * 60 * 1e3);
1684
+ const startWall = wallClockParts(instant, targetTimezone);
1685
+ const endWall = wallClockParts(end, targetTimezone);
1686
+ const targetOffset = timeZoneOffsetString(targetTimezone, instant);
1687
+ const toIso = (w2) => `${w2.year}-${pad2(w2.month)}-${pad2(w2.day)}T${pad2(w2.hour)}:${pad2(w2.minute)}:${pad2(w2.second)}${targetOffset}`;
1688
+ const formatClock = (hour24, min) => {
1689
+ const hour12 = hour24 % 12 || 12;
1690
+ const ampm = hour24 >= 12 ? "PM" : "AM";
1691
+ return { label: `${hour12}:${pad2(min)}${ampm}`, hour12, ampm };
1692
+ };
1693
+ const weekdayLabel = WEEKDAYS[new Date(startWall.year, startWall.month - 1, startWall.day).getDay()] ?? "Tuesday";
1694
+ const monthLabel = MONTHS[startWall.month - 1] ?? "June";
1695
+ const dateLabel = `${weekdayLabel}, ${monthLabel} ${pad2(startWall.day)}, ${startWall.year}`;
1696
+ const start = formatClock(startWall.hour, startWall.minute);
1697
+ const slotEnd = formatClock(endWall.hour, endWall.minute);
1600
1698
  slots.push({
1601
- start_time: toIso(start),
1602
- end_time: toIso(end),
1603
- day,
1604
- month: pad(start.getMonth() + 1),
1605
- year,
1606
- hour: String(hour12),
1607
- minute,
1608
- am_or_pm: ampm,
1609
- weekday,
1610
- invitee_start_time: `${hour12}:${minute}${ampm} - ${weekday}, ${monthLabel} ${day}, ${year}`,
1611
- invitee_end_time: `${endHour12}:${pad(end.getMinutes())}${endAmpm} - ${weekday}, ${monthLabel} ${day}, ${year}`
1699
+ start_time: toIso(startWall),
1700
+ end_time: toIso(endWall),
1701
+ utc_start_time: instant.toISOString(),
1702
+ utc_end_time: end.toISOString(),
1703
+ day: pad2(startWall.day),
1704
+ month: pad2(startWall.month),
1705
+ year: String(startWall.year),
1706
+ hour: String(start.hour12),
1707
+ minute: pad2(startWall.minute),
1708
+ second: pad2(startWall.second),
1709
+ am_or_pm: start.ampm,
1710
+ weekday: weekdayLabel,
1711
+ invitee_start_time: `${start.label} - ${dateLabel}`,
1712
+ invitee_end_time: `${slotEnd.label} - ${dateLabel}`,
1713
+ webinar_lead_type: webinarType
1612
1714
  });
1613
1715
  }
1614
1716
  return slots;
@@ -1675,12 +1777,12 @@ var IKEmbeddableFormBundle = function(exports) {
1675
1777
  const slots = Array.isArray(data) ? data : [];
1676
1778
  return slots;
1677
1779
  }
1678
- function getStaticSlots(openConfig) {
1780
+ function getStaticSlots(openConfig, country, timezone, webinarType) {
1679
1781
  const custom = openConfig == null ? void 0 : openConfig.staticSlots;
1680
1782
  if (custom && custom.length > 0) {
1681
1783
  return custom;
1682
1784
  }
1683
- return createFutureStaticSlots();
1785
+ return generateFallbackSlots(country, timezone, webinarType);
1684
1786
  }
1685
1787
  function resolveSlotApiCountry(openConfig, slotApiConfig) {
1686
1788
  if (openConfig == null ? void 0 : openConfig.slotApiCountry) {
@@ -1723,20 +1825,18 @@ var IKEmbeddableFormBundle = function(exports) {
1723
1825
  return {
1724
1826
  slots: l2.map(apiSlotToWebinarSlot),
1725
1827
  rawSlots: l2,
1726
- assignedWebinarType: "REGULAR",
1828
+ assignedWebinarType: l2Type,
1727
1829
  source: "api-l2"
1728
1830
  };
1729
1831
  }
1730
1832
  } catch {
1731
1833
  }
1732
- const staticSlots = filterFutureSlots(getStaticSlots(openConfig));
1733
- const fallback = limitDisplaySlots(
1734
- staticSlots.length > 0 ? staticSlots : filterFutureSlots(createFutureStaticSlots())
1735
- );
1834
+ const staticSlots = filterFutureSlots(getStaticSlots(openConfig, country, timezone, l2Type));
1835
+ const fallback = limitDisplaySlots(staticSlots);
1736
1836
  return {
1737
1837
  slots: fallback.map(apiSlotToWebinarSlot),
1738
1838
  rawSlots: fallback,
1739
- assignedWebinarType: webinarType,
1839
+ assignedWebinarType: l2Type,
1740
1840
  source: "static"
1741
1841
  };
1742
1842
  }
@@ -1950,8 +2050,7 @@ var IKEmbeddableFormBundle = function(exports) {
1950
2050
  Region: formData.region ?? (ctx == null ? void 0 : ctx.region) ?? "",
1951
2051
  step,
1952
2052
  data_click_id: resolveClickId(formData),
1953
- ab_bucket_json: JSON.stringify({ gql_yoe_dropdown_ab: "" }),
1954
- fingerprint_id: getFingerprintId()
2053
+ ab_bucket_json: JSON.stringify({ gql_yoe_dropdown_ab: "" })
1955
2054
  };
1956
2055
  }
1957
2056
  async function postClickstream(url, apiKey, datasetId, tableId, row) {
@@ -2364,13 +2463,13 @@ var IKEmbeddableFormBundle = function(exports) {
2364
2463
  }
2365
2464
  startSlotsPrefetch() {
2366
2465
  if (!this.needsSlotsPrefetch() || this.slotsPrefetchPromise) return;
2367
- this.mergeFormData({ slotsLoading: true }, true);
2466
+ this.mergeFormData({ slotsLoading: true });
2368
2467
  const earlyPrefetch = getSlotsPrefetchPromise();
2369
2468
  const prefetch = earlyPrefetch ? earlyPrefetch.then((result) => {
2370
2469
  this.applySlotFetchResult(result);
2371
2470
  }) : this.loadSlotsIntoFormData();
2372
2471
  this.slotsPrefetchPromise = prefetch.catch((err) => {
2373
- this.mergeFormData({ slotsLoading: false }, true);
2472
+ this.patchFormData({ slotsLoading: false });
2374
2473
  this.analytics.trackError(err, {
2375
2474
  stepId: "prefetch-slots",
2376
2475
  formId: this.config.id
@@ -2400,7 +2499,7 @@ var IKEmbeddableFormBundle = function(exports) {
2400
2499
  patch.inviteeEndTime = firstSlot.inviteeEndTime;
2401
2500
  patch.slotDisplay = formatInviteeDisplay(firstSlot.inviteeStartTime, firstSlot.startTime);
2402
2501
  }
2403
- this.mergeFormData(patch, true);
2502
+ this.patchFormData(patch);
2404
2503
  }
2405
2504
  async ensureSlotsReady(step) {
2406
2505
  if (this.slotsPrefetchPromise) {
@@ -2737,18 +2836,23 @@ var IKEmbeddableFormBundle = function(exports) {
2737
2836
  });
2738
2837
  return data;
2739
2838
  }
2740
- mergeFormData(incoming, notify = false) {
2839
+ mergeFormData(incoming) {
2741
2840
  this.state = {
2742
2841
  ...this.state,
2743
2842
  formData: { ...this.state.formData, ...incoming }
2744
2843
  };
2745
- if (notify) this.notifyListeners();
2844
+ }
2845
+ /**
2846
+ * Like `mergeFormData`, but notifies subscribers so the UI re-renders.
2847
+ * Needed for data that arrives asynchronously while a step is already on screen
2848
+ * (slot prefetch), where `mergeFormData` alone leaves the view stale until the
2849
+ * next unrelated `setState`.
2850
+ */
2851
+ patchFormData(incoming) {
2852
+ this.setState({ formData: { ...this.state.formData, ...incoming } });
2746
2853
  }
2747
2854
  setState(partial) {
2748
2855
  this.state = { ...this.state, ...partial };
2749
- this.notifyListeners();
2750
- }
2751
- notifyListeners() {
2752
2856
  this.listeners.forEach((l2) => l2(this.getState()));
2753
2857
  }
2754
2858
  }
@@ -2884,10 +2988,6 @@ var IKEmbeddableFormBundle = function(exports) {
2884
2988
  lastName: parts.slice(1).join(" ") || (parts[0] ?? "")
2885
2989
  };
2886
2990
  }
2887
- function customerIdFields(context) {
2888
- const customerId = str(context.openConfig.customerId);
2889
- return customerId ? { customer_id: customerId } : {};
2890
- }
2891
2991
  function resolveUtmMedium(context) {
2892
2992
  return resolveWordPressUtmMedium(
2893
2993
  context.visitorId,
@@ -2915,7 +3015,6 @@ var IKEmbeddableFormBundle = function(exports) {
2915
3015
  const { firstName, lastName } = resolveName(formData);
2916
3016
  const webinarType = resolveEffectiveWebinarType(formData, context.webinarType);
2917
3017
  return {
2918
- ...customerIdFields(context),
2919
3018
  "First Name": firstName,
2920
3019
  "Last Name": lastName,
2921
3020
  "Email Address": email(formData.email),
@@ -2995,7 +3094,6 @@ var IKEmbeddableFormBundle = function(exports) {
2995
3094
  const gaEventId = Date.now();
2996
3095
  const { firstName, lastName } = resolveName(formData);
2997
3096
  return {
2998
- ...customerIdFields(context),
2999
3097
  "First Name": firstName,
3000
3098
  "Last Name": lastName,
3001
3099
  "Email Address": email(formData.email),
@@ -3067,7 +3165,6 @@ var IKEmbeddableFormBundle = function(exports) {
3067
3165
  const linkedIn = str(formData.linkedIn).trim();
3068
3166
  const resumeBase64 = str(formData.resumeFileBase64).trim();
3069
3167
  return {
3070
- ...customerIdFields(context),
3071
3168
  Lead_Created_Time: formatLeadCreatedTime(formData.leadCreatedTime),
3072
3169
  Page_URL: encodeURIComponent(context.pageUrl),
3073
3170
  "First Name": firstName,
@@ -3190,10 +3287,6 @@ var IKEmbeddableFormBundle = function(exports) {
3190
3287
  return url.toString();
3191
3288
  }
3192
3289
  buildBody(contract, formData) {
3193
- const body = this.buildRawBody(contract, formData);
3194
- return { ...body, fingerprint_id: getFingerprintId() };
3195
- }
3196
- buildRawBody(contract, formData) {
3197
3290
  if (contract.payloadBuilder) {
3198
3291
  return buildPayload(contract.payloadBuilder, formData);
3199
3292
  }
@@ -3218,13 +3311,7 @@ var IKEmbeddableFormBundle = function(exports) {
3218
3311
  }
3219
3312
  async fetchWithRetry(url, init, retriesLeft, timeoutMs) {
3220
3313
  const controller = new AbortController();
3221
- let timedOut = false;
3222
- const timeoutId = setTimeout(() => {
3223
- timedOut = true;
3224
- controller.abort(
3225
- new DOMException(`Request timed out after ${timeoutMs}ms`, "TimeoutError")
3226
- );
3227
- }, timeoutMs);
3314
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
3228
3315
  try {
3229
3316
  const res = await fetch(url, { ...init, signal: controller.signal });
3230
3317
  clearTimeout(timeoutId);
@@ -3241,21 +3328,13 @@ var IKEmbeddableFormBundle = function(exports) {
3241
3328
  return { data, status: res.status, ok: true };
3242
3329
  } catch (err) {
3243
3330
  clearTimeout(timeoutId);
3244
- const normalizedErr = timedOut ? this.buildTimeoutError(timeoutMs) : err;
3245
- if (retriesLeft > 1 && this.isRetryable(normalizedErr)) {
3331
+ if (retriesLeft > 1 && this.isRetryable(err)) {
3246
3332
  await this.delay(500 * (2 - retriesLeft));
3247
3333
  return this.fetchWithRetry(url, init, retriesLeft - 1, timeoutMs);
3248
3334
  }
3249
- throw normalizedErr;
3335
+ throw err;
3250
3336
  }
3251
3337
  }
3252
- buildTimeoutError(timeoutMs) {
3253
- return {
3254
- code: "TIMEOUT",
3255
- message: "This is taking longer than expected. Please try again.",
3256
- details: { timeoutMs }
3257
- };
3258
- }
3259
3338
  applyResponseMapping(mapping, response) {
3260
3339
  if (!mapping) return {};
3261
3340
  const result = {};
@@ -3271,7 +3350,7 @@ var IKEmbeddableFormBundle = function(exports) {
3271
3350
  if (err instanceof TypeError) return true;
3272
3351
  if (err && typeof err === "object" && "code" in err) {
3273
3352
  const code = err.code;
3274
- return code === "TIMEOUT" || code === "HTTP_429" || code === "HTTP_503" || code === "HTTP_502";
3353
+ return code === "HTTP_429" || code === "HTTP_503" || code === "HTTP_502";
3275
3354
  }
3276
3355
  return false;
3277
3356
  }
@@ -21616,49 +21695,10 @@ var IKEmbeddableFormBundle = function(exports) {
21616
21695
  }
21617
21696
  }
21618
21697
  };
21619
- const emailRegistrationVariant = {
21620
- id: "email-registration",
21621
- overrides: {
21622
- layout: {
21623
- leftPanel: {
21624
- progressGroups: [
21625
- {
21626
- number: 1,
21627
- title: "Webinar Registration",
21628
- stepIds: ["slot-selection"]
21629
- },
21630
- {
21631
- number: 2,
21632
- title: "Profile Details",
21633
- stepIds: ["profile-details", "goals-details"]
21634
- }
21635
- ]
21636
- },
21637
- rightPanel: {
21638
- progressGroups: [
21639
- { stepIds: ["slot-selection"] },
21640
- { stepIds: ["profile-details"] },
21641
- { stepIds: ["goals-details"] },
21642
- { stepIds: ["consultation-prefs"] }
21643
- ]
21644
- }
21645
- },
21646
- steps: {
21647
- // Lead is resolved from customer_id on the backend — skip contact collection.
21648
- "contact-details": { show: false },
21649
- "profile-details": {
21650
- fields: {
21651
- interviewTimeline: { show: false }
21652
- }
21653
- }
21654
- }
21655
- }
21656
- };
21657
21698
  const GQL_WEBINAR_VARIANTS = [
21658
21699
  defaultVariant,
21659
21700
  indiaVariant,
21660
- eventVariant,
21661
- emailRegistrationVariant
21701
+ eventVariant
21662
21702
  ];
21663
21703
  const gqlWebinarConfig = {
21664
21704
  ...gqlWebinarBaseConfig,
@@ -21822,7 +21862,7 @@ ${intlTelStyles}`;
21822
21862
  destroy();
21823
21863
  },
21824
21864
  getVersion() {
21825
- return "1.0.35";
21865
+ return "1.0.36";
21826
21866
  },
21827
21867
  /**
21828
21868
  * Allowlisted snapshot of everything the user has submitted so far.