myio-js-library 0.1.261 → 0.1.264

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/index.cjs CHANGED
@@ -9280,6 +9280,8 @@ var EnergyRangeTooltip = {
9280
9280
  var LABEL_CHAR_LIMIT = 18;
9281
9281
  var DEFAUL_DELAY_TIME_CONNECTION_IN_MINS = 1440;
9282
9282
  var CSS_TAG = "head-office-card-v1";
9283
+ var _warnedMissingEntityId = false;
9284
+ var _warnedMissingDelayTime = false;
9283
9285
  function ensureCss() {
9284
9286
  if (!document.querySelector(`style[data-myio-css="${CSS_TAG}"]`)) {
9285
9287
  const style = document.createElement("style");
@@ -9295,13 +9297,19 @@ function normalizeParams(params) {
9295
9297
  const LogHelper2 = createLogHelper(params.debugActive ?? false);
9296
9298
  const entityObject = params.entityObject;
9297
9299
  if (!entityObject.entityId) {
9298
- LogHelper2.warn("[CardHeadOffice] entityId is missing, generating temporary ID");
9300
+ if (!_warnedMissingEntityId) {
9301
+ _warnedMissingEntityId = true;
9302
+ LogHelper2.warn("[CardHeadOffice] entityId is missing on some devices, generating temporary IDs");
9303
+ }
9299
9304
  entityObject.entityId = `temp-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
9300
9305
  }
9301
9306
  if (!params.delayTimeConnectionInMins) {
9302
- LogHelper2.warn(
9303
- `[CardHeadOffice] delayTimeConnectionInMins is missing, defaulting to ${DEFAUL_DELAY_TIME_CONNECTION_IN_MINS} mins`
9304
- );
9307
+ if (!_warnedMissingDelayTime) {
9308
+ _warnedMissingDelayTime = true;
9309
+ LogHelper2.warn(
9310
+ `[CardHeadOffice] delayTimeConnectionInMins is missing, defaulting to ${DEFAUL_DELAY_TIME_CONNECTION_IN_MINS} mins`
9311
+ );
9312
+ }
9305
9313
  }
9306
9314
  return {
9307
9315
  entityObject,
@@ -9792,26 +9800,10 @@ function verifyOfflineStatus(entityObject, delayTimeInMins = 15, LogHelper2) {
9792
9800
  let isOffline = false;
9793
9801
  if (lastDisconnectTime.getTime() > lastConnectionTime.getTime()) {
9794
9802
  isOffline = true;
9795
- LogHelper2.log(
9796
- "[CardHeadOffice][ConnectionStatus Verify] Device is OFFLINE because lastDisconnectTime is more recent than lastConnectTime",
9797
- entityObject.nameEl
9798
- );
9799
9803
  } else if (timeSinceConnection > delayTimeInMs) {
9800
9804
  isOffline = true;
9801
- LogHelper2.log(
9802
- "[CardHeadOffice][ConnectionStatus Verify] Device is OFFLINE because lastConnectTime is older than configured delayTimeConnectionInMins:",
9803
- delayTimeInMins,
9804
- "for device",
9805
- entityObject.nameEl
9806
- );
9807
9805
  } else {
9808
9806
  isOffline = false;
9809
- LogHelper2.log(
9810
- "[CardHeadOffice][ConnectionStatus Verify] Device is ONLINE because lastConnectTime is within configured delayTimeConnectionInMins:",
9811
- delayTimeInMins,
9812
- "for device",
9813
- entityObject.nameEl
9814
- );
9815
9807
  }
9816
9808
  return isOffline;
9817
9809
  }
@@ -9820,30 +9812,16 @@ function paint(root, state6) {
9820
9812
  let statusDecisionSource = "unknown";
9821
9813
  if (entityObject.connectionStatus) {
9822
9814
  if (entityObject.connectionStatus === "offline") {
9823
- LogHelper2.log(
9824
- "[CardHeadOffice][ConnectionStatus Verify 01] Setting deviceStatus to OFFLINE based on connectionStatus"
9825
- );
9826
9815
  entityObject.deviceStatus = DeviceStatusType.OFFLINE;
9827
9816
  statusDecisionSource = 'connectionStatus === "offline"';
9828
9817
  } else {
9829
- LogHelper2.log(
9830
- "[CardHeadOffice] Device is ONLINE or WAITING based on connectionStatus for device",
9831
- entityObject.nameEl
9832
- );
9833
9818
  statusDecisionSource = `connectionStatus === "${entityObject.connectionStatus}" (kept original deviceStatus)`;
9834
9819
  }
9835
9820
  } else {
9836
9821
  if (verifyOfflineStatus(entityObject, delayTimeConnectionInMins, LogHelper2) === false) {
9837
- LogHelper2.log(
9838
- "[CardHeadOffice][ConnectionStatus Verify 02] Setting deviceStatus to OFFLINE based on timestamp verification by verifyOfflineStatus METHOD with delayTimeConnectionInMins:",
9839
- delayTimeConnectionInMins
9840
- );
9841
9822
  entityObject.deviceStatus = DeviceStatusType.OFFLINE;
9842
9823
  statusDecisionSource = `verifyOfflineStatus() returned false (delay: ${delayTimeConnectionInMins} mins)`;
9843
9824
  } else {
9844
- LogHelper2.log(
9845
- `[CardHeadOffice][ConnectionStatus Verify 03] Device is ONLINE with deviceStatus = ${entityObject.deviceStatus} based on timestamp verification for device ${entityObject.nameEl}`
9846
- );
9847
9825
  statusDecisionSource = `verifyOfflineStatus() returned true (delay: ${delayTimeConnectionInMins} mins)`;
9848
9826
  }
9849
9827
  }
@@ -26378,9 +26356,43 @@ var WelcomeModalView = class {
26378
26356
  userEmailEl.textContent = this.params.userInfo.email;
26379
26357
  return;
26380
26358
  }
26359
+ const getToken = () => {
26360
+ const tokenKeys = ["jwt_token", "access_token", "authToken", "tb_token"];
26361
+ for (const key of tokenKeys) {
26362
+ const token = localStorage.getItem(key);
26363
+ if (token) return token;
26364
+ }
26365
+ for (const key of tokenKeys) {
26366
+ const token = sessionStorage.getItem(key);
26367
+ if (token) return token;
26368
+ }
26369
+ const win = window;
26370
+ if (win.AuthService?.jwtToken) return win.AuthService.jwtToken;
26371
+ const cookies = document.cookie.split(";");
26372
+ for (const cookie of cookies) {
26373
+ const [name, value] = cookie.trim().split("=");
26374
+ if (tokenKeys.includes(name)) return value;
26375
+ }
26376
+ return null;
26377
+ };
26381
26378
  try {
26382
- const token = localStorage.getItem("jwt_token");
26379
+ const token = getToken();
26383
26380
  if (!token) {
26381
+ const ctx = this.params.ctx;
26382
+ if (ctx?.currentUser) {
26383
+ const user = ctx.currentUser;
26384
+ const fullName = [user.firstName, user.lastName].filter(Boolean).join(" ") || user.name || "Usu\xE1rio";
26385
+ userNameEl.textContent = fullName;
26386
+ userEmailEl.textContent = user.email || "";
26387
+ return;
26388
+ }
26389
+ const tbUser = window.tb_user;
26390
+ if (tbUser) {
26391
+ const fullName = [tbUser.firstName, tbUser.lastName].filter(Boolean).join(" ") || tbUser.name || "Usu\xE1rio";
26392
+ userNameEl.textContent = fullName;
26393
+ userEmailEl.textContent = tbUser.email || "";
26394
+ return;
26395
+ }
26384
26396
  userNameEl.textContent = "Usu\xE1rio";
26385
26397
  userEmailEl.textContent = "";
26386
26398
  return;
@@ -26414,6 +26426,124 @@ var WelcomeModalView = class {
26414
26426
  if (userNameEl) userNameEl.textContent = info.fullName;
26415
26427
  if (userEmailEl) userEmailEl.textContent = info.email;
26416
26428
  }
26429
+ /**
26430
+ * Update shopping cards after data loads (RFC-0111: loading state support)
26431
+ */
26432
+ updateShoppingCards(cards) {
26433
+ this.params.shoppingCards = cards;
26434
+ let shortcutsSection = this.container.querySelector(".myio-welcome-shortcuts");
26435
+ const modalContainer = this.container.querySelector(".myio-welcome-modal-container");
26436
+ if (cards.length === 0) {
26437
+ if (shortcutsSection) {
26438
+ shortcutsSection.remove();
26439
+ }
26440
+ return;
26441
+ }
26442
+ const shortcutsTitle = this.params.shortcutsTitle ?? this.config.defaultShortcutsTitle ?? "Acesso R\xE1pido aos Shoppings";
26443
+ const themeConfig = this.getThemeConfig();
26444
+ const shortcutsTitleColor = themeConfig.shortcutsTitleColor ?? themeConfig.mutedTextColor;
26445
+ if (!shortcutsSection && modalContainer) {
26446
+ shortcutsSection = document.createElement("div");
26447
+ shortcutsSection.className = "myio-welcome-shortcuts";
26448
+ modalContainer.appendChild(shortcutsSection);
26449
+ }
26450
+ if (shortcutsSection) {
26451
+ shortcutsSection.innerHTML = `
26452
+ <h2 class="myio-welcome-shortcuts-title"${shortcutsTitleColor ? ` style="color: ${shortcutsTitleColor}"` : ""}>${shortcutsTitle}</h2>
26453
+ <div class="myio-welcome-cards-grid" id="welcomeCardsGrid">
26454
+ ${cards.map((card, index) => this.buildCardHTML(card, index)).join("")}
26455
+ </div>
26456
+ `;
26457
+ this.bindCardEvents();
26458
+ this.setupLazyLoading();
26459
+ }
26460
+ if (this.config.enableDebugMode) {
26461
+ console.log("[WelcomeModal] Shopping cards updated:", cards.length);
26462
+ }
26463
+ }
26464
+ /**
26465
+ * Bind events for shopping cards (used after dynamic update)
26466
+ */
26467
+ bindCardEvents() {
26468
+ const cards = this.container.querySelectorAll(".myio-welcome-card");
26469
+ cards.forEach((card, index) => {
26470
+ const shoppingCard = this.params.shoppingCards?.[index];
26471
+ if (!shoppingCard) return;
26472
+ card.addEventListener("click", (e) => {
26473
+ const target = e.target;
26474
+ if (target.closest(".myio-welcome-card-device-count")) {
26475
+ return;
26476
+ }
26477
+ this.emit("card-click", shoppingCard);
26478
+ });
26479
+ card.addEventListener("keydown", (e) => {
26480
+ const keyEvent = e;
26481
+ if (keyEvent.key === "Enter" || keyEvent.key === " ") {
26482
+ e.preventDefault();
26483
+ this.emit("card-click", shoppingCard);
26484
+ }
26485
+ });
26486
+ });
26487
+ this.bindTooltipEvents();
26488
+ }
26489
+ /**
26490
+ * Set CTA button label
26491
+ */
26492
+ setCtaLabel(label) {
26493
+ const ctaBtn = this.container.querySelector("#welcomeCtaBtn");
26494
+ if (ctaBtn) {
26495
+ const svgIcon = ctaBtn.querySelector("svg");
26496
+ ctaBtn.textContent = "";
26497
+ ctaBtn.appendChild(document.createTextNode(label + " "));
26498
+ if (svgIcon) {
26499
+ ctaBtn.appendChild(svgIcon);
26500
+ } else {
26501
+ const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
26502
+ svg.setAttribute("viewBox", "0 0 24 24");
26503
+ svg.setAttribute("fill", "none");
26504
+ svg.setAttribute("stroke", "currentColor");
26505
+ svg.setAttribute("stroke-width", "2");
26506
+ svg.setAttribute("stroke-linecap", "round");
26507
+ svg.setAttribute("stroke-linejoin", "round");
26508
+ svg.innerHTML = '<line x1="5" y1="12" x2="19" y2="12" /><polyline points="12 5 19 12 12 19" />';
26509
+ ctaBtn.appendChild(svg);
26510
+ }
26511
+ }
26512
+ }
26513
+ /**
26514
+ * Set CTA button disabled state
26515
+ */
26516
+ setCtaDisabled(disabled) {
26517
+ const ctaBtn = this.container.querySelector("#welcomeCtaBtn");
26518
+ if (ctaBtn) {
26519
+ ctaBtn.disabled = disabled;
26520
+ ctaBtn.style.opacity = disabled ? "0.5" : "1";
26521
+ ctaBtn.style.cursor = disabled ? "not-allowed" : "pointer";
26522
+ }
26523
+ }
26524
+ /**
26525
+ * Show the modal (after it was hidden)
26526
+ */
26527
+ show() {
26528
+ this.container.style.display = "flex";
26529
+ this.container.style.opacity = "0";
26530
+ requestAnimationFrame(() => {
26531
+ this.container.style.opacity = "1";
26532
+ this.container.style.transition = "opacity 0.3s ease";
26533
+ });
26534
+ document.body.style.overflow = "hidden";
26535
+ }
26536
+ /**
26537
+ * Hide the modal (without destroying it)
26538
+ */
26539
+ hide() {
26540
+ this.container.style.opacity = "0";
26541
+ this.container.style.transition = "opacity 0.3s ease";
26542
+ setTimeout(() => {
26543
+ this.container.style.display = "none";
26544
+ document.body.style.overflow = "";
26545
+ }, 300);
26546
+ }
26417
26547
  /**
26418
26548
  * Cleanup resources
26419
26549
  */
@@ -26534,8 +26664,15 @@ function openWelcomeModal(params) {
26534
26664
  element.style.opacity = "1";
26535
26665
  element.style.transition = "opacity 0.3s ease";
26536
26666
  });
26667
+ function open() {
26668
+ if (!element.parentNode) {
26669
+ document.body.appendChild(element);
26670
+ }
26671
+ view.show();
26672
+ }
26537
26673
  return {
26538
26674
  close,
26675
+ open,
26539
26676
  element,
26540
26677
  on: (event, handler) => {
26541
26678
  if (event === "close") {
@@ -26545,7 +26682,15 @@ function openWelcomeModal(params) {
26545
26682
  /** Set the theme mode from outside (e.g., from MAIN component) */
26546
26683
  setThemeMode: (mode) => view.setThemeMode(mode),
26547
26684
  /** Get the current theme mode */
26548
- getThemeMode: () => view.getThemeMode()
26685
+ getThemeMode: () => view.getThemeMode(),
26686
+ /** Update shopping cards after data loads (RFC-0111: loading state) */
26687
+ updateShoppingCards: (cards) => view.updateShoppingCards(cards),
26688
+ /** Update user info display */
26689
+ updateUserInfo: (info) => view.updateUserInfo(info),
26690
+ /** Set CTA button label */
26691
+ setCtaLabel: (label) => view.setCtaLabel(label),
26692
+ /** Set CTA button disabled state */
26693
+ setCtaDisabled: (disabled) => view.setCtaDisabled(disabled)
26549
26694
  };
26550
26695
  }
26551
26696
 
package/dist/index.d.cts CHANGED
@@ -2788,6 +2788,8 @@ interface WelcomeModalParams {
2788
2788
  interface WelcomeModalInstance {
2789
2789
  /** Close the modal programmatically */
2790
2790
  close: () => void;
2791
+ /** Open/show the modal again after it was closed */
2792
+ open: () => void;
2791
2793
  /** The modal's root DOM element */
2792
2794
  element: HTMLElement;
2793
2795
  /** Register event handlers */
@@ -2796,6 +2798,14 @@ interface WelcomeModalInstance {
2796
2798
  setThemeMode: (mode: WelcomeThemeMode) => void;
2797
2799
  /** Get the current theme mode */
2798
2800
  getThemeMode: () => WelcomeThemeMode;
2801
+ /** Update shopping cards after data loads (RFC-0111: loading state) */
2802
+ updateShoppingCards: (cards: ShoppingCard[]) => void;
2803
+ /** Update user info display */
2804
+ updateUserInfo: (info: UserInfo$1) => void;
2805
+ /** Set CTA button label */
2806
+ setCtaLabel: (label: string) => void;
2807
+ /** Set CTA button disabled state */
2808
+ setCtaDisabled: (disabled: boolean) => void;
2799
2809
  }
2800
2810
  /**
2801
2811
  * Default palette values
package/dist/index.js CHANGED
@@ -9063,6 +9063,8 @@ var EnergyRangeTooltip = {
9063
9063
  var LABEL_CHAR_LIMIT = 18;
9064
9064
  var DEFAUL_DELAY_TIME_CONNECTION_IN_MINS = 1440;
9065
9065
  var CSS_TAG = "head-office-card-v1";
9066
+ var _warnedMissingEntityId = false;
9067
+ var _warnedMissingDelayTime = false;
9066
9068
  function ensureCss() {
9067
9069
  if (!document.querySelector(`style[data-myio-css="${CSS_TAG}"]`)) {
9068
9070
  const style = document.createElement("style");
@@ -9078,13 +9080,19 @@ function normalizeParams(params) {
9078
9080
  const LogHelper2 = createLogHelper(params.debugActive ?? false);
9079
9081
  const entityObject = params.entityObject;
9080
9082
  if (!entityObject.entityId) {
9081
- LogHelper2.warn("[CardHeadOffice] entityId is missing, generating temporary ID");
9083
+ if (!_warnedMissingEntityId) {
9084
+ _warnedMissingEntityId = true;
9085
+ LogHelper2.warn("[CardHeadOffice] entityId is missing on some devices, generating temporary IDs");
9086
+ }
9082
9087
  entityObject.entityId = `temp-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
9083
9088
  }
9084
9089
  if (!params.delayTimeConnectionInMins) {
9085
- LogHelper2.warn(
9086
- `[CardHeadOffice] delayTimeConnectionInMins is missing, defaulting to ${DEFAUL_DELAY_TIME_CONNECTION_IN_MINS} mins`
9087
- );
9090
+ if (!_warnedMissingDelayTime) {
9091
+ _warnedMissingDelayTime = true;
9092
+ LogHelper2.warn(
9093
+ `[CardHeadOffice] delayTimeConnectionInMins is missing, defaulting to ${DEFAUL_DELAY_TIME_CONNECTION_IN_MINS} mins`
9094
+ );
9095
+ }
9088
9096
  }
9089
9097
  return {
9090
9098
  entityObject,
@@ -9575,26 +9583,10 @@ function verifyOfflineStatus(entityObject, delayTimeInMins = 15, LogHelper2) {
9575
9583
  let isOffline = false;
9576
9584
  if (lastDisconnectTime.getTime() > lastConnectionTime.getTime()) {
9577
9585
  isOffline = true;
9578
- LogHelper2.log(
9579
- "[CardHeadOffice][ConnectionStatus Verify] Device is OFFLINE because lastDisconnectTime is more recent than lastConnectTime",
9580
- entityObject.nameEl
9581
- );
9582
9586
  } else if (timeSinceConnection > delayTimeInMs) {
9583
9587
  isOffline = true;
9584
- LogHelper2.log(
9585
- "[CardHeadOffice][ConnectionStatus Verify] Device is OFFLINE because lastConnectTime is older than configured delayTimeConnectionInMins:",
9586
- delayTimeInMins,
9587
- "for device",
9588
- entityObject.nameEl
9589
- );
9590
9588
  } else {
9591
9589
  isOffline = false;
9592
- LogHelper2.log(
9593
- "[CardHeadOffice][ConnectionStatus Verify] Device is ONLINE because lastConnectTime is within configured delayTimeConnectionInMins:",
9594
- delayTimeInMins,
9595
- "for device",
9596
- entityObject.nameEl
9597
- );
9598
9590
  }
9599
9591
  return isOffline;
9600
9592
  }
@@ -9603,30 +9595,16 @@ function paint(root, state6) {
9603
9595
  let statusDecisionSource = "unknown";
9604
9596
  if (entityObject.connectionStatus) {
9605
9597
  if (entityObject.connectionStatus === "offline") {
9606
- LogHelper2.log(
9607
- "[CardHeadOffice][ConnectionStatus Verify 01] Setting deviceStatus to OFFLINE based on connectionStatus"
9608
- );
9609
9598
  entityObject.deviceStatus = DeviceStatusType.OFFLINE;
9610
9599
  statusDecisionSource = 'connectionStatus === "offline"';
9611
9600
  } else {
9612
- LogHelper2.log(
9613
- "[CardHeadOffice] Device is ONLINE or WAITING based on connectionStatus for device",
9614
- entityObject.nameEl
9615
- );
9616
9601
  statusDecisionSource = `connectionStatus === "${entityObject.connectionStatus}" (kept original deviceStatus)`;
9617
9602
  }
9618
9603
  } else {
9619
9604
  if (verifyOfflineStatus(entityObject, delayTimeConnectionInMins, LogHelper2) === false) {
9620
- LogHelper2.log(
9621
- "[CardHeadOffice][ConnectionStatus Verify 02] Setting deviceStatus to OFFLINE based on timestamp verification by verifyOfflineStatus METHOD with delayTimeConnectionInMins:",
9622
- delayTimeConnectionInMins
9623
- );
9624
9605
  entityObject.deviceStatus = DeviceStatusType.OFFLINE;
9625
9606
  statusDecisionSource = `verifyOfflineStatus() returned false (delay: ${delayTimeConnectionInMins} mins)`;
9626
9607
  } else {
9627
- LogHelper2.log(
9628
- `[CardHeadOffice][ConnectionStatus Verify 03] Device is ONLINE with deviceStatus = ${entityObject.deviceStatus} based on timestamp verification for device ${entityObject.nameEl}`
9629
- );
9630
9608
  statusDecisionSource = `verifyOfflineStatus() returned true (delay: ${delayTimeConnectionInMins} mins)`;
9631
9609
  }
9632
9610
  }
@@ -26161,9 +26139,43 @@ var WelcomeModalView = class {
26161
26139
  userEmailEl.textContent = this.params.userInfo.email;
26162
26140
  return;
26163
26141
  }
26142
+ const getToken = () => {
26143
+ const tokenKeys = ["jwt_token", "access_token", "authToken", "tb_token"];
26144
+ for (const key of tokenKeys) {
26145
+ const token = localStorage.getItem(key);
26146
+ if (token) return token;
26147
+ }
26148
+ for (const key of tokenKeys) {
26149
+ const token = sessionStorage.getItem(key);
26150
+ if (token) return token;
26151
+ }
26152
+ const win = window;
26153
+ if (win.AuthService?.jwtToken) return win.AuthService.jwtToken;
26154
+ const cookies = document.cookie.split(";");
26155
+ for (const cookie of cookies) {
26156
+ const [name, value] = cookie.trim().split("=");
26157
+ if (tokenKeys.includes(name)) return value;
26158
+ }
26159
+ return null;
26160
+ };
26164
26161
  try {
26165
- const token = localStorage.getItem("jwt_token");
26162
+ const token = getToken();
26166
26163
  if (!token) {
26164
+ const ctx = this.params.ctx;
26165
+ if (ctx?.currentUser) {
26166
+ const user = ctx.currentUser;
26167
+ const fullName = [user.firstName, user.lastName].filter(Boolean).join(" ") || user.name || "Usu\xE1rio";
26168
+ userNameEl.textContent = fullName;
26169
+ userEmailEl.textContent = user.email || "";
26170
+ return;
26171
+ }
26172
+ const tbUser = window.tb_user;
26173
+ if (tbUser) {
26174
+ const fullName = [tbUser.firstName, tbUser.lastName].filter(Boolean).join(" ") || tbUser.name || "Usu\xE1rio";
26175
+ userNameEl.textContent = fullName;
26176
+ userEmailEl.textContent = tbUser.email || "";
26177
+ return;
26178
+ }
26167
26179
  userNameEl.textContent = "Usu\xE1rio";
26168
26180
  userEmailEl.textContent = "";
26169
26181
  return;
@@ -26197,6 +26209,124 @@ var WelcomeModalView = class {
26197
26209
  if (userNameEl) userNameEl.textContent = info.fullName;
26198
26210
  if (userEmailEl) userEmailEl.textContent = info.email;
26199
26211
  }
26212
+ /**
26213
+ * Update shopping cards after data loads (RFC-0111: loading state support)
26214
+ */
26215
+ updateShoppingCards(cards) {
26216
+ this.params.shoppingCards = cards;
26217
+ let shortcutsSection = this.container.querySelector(".myio-welcome-shortcuts");
26218
+ const modalContainer = this.container.querySelector(".myio-welcome-modal-container");
26219
+ if (cards.length === 0) {
26220
+ if (shortcutsSection) {
26221
+ shortcutsSection.remove();
26222
+ }
26223
+ return;
26224
+ }
26225
+ const shortcutsTitle = this.params.shortcutsTitle ?? this.config.defaultShortcutsTitle ?? "Acesso R\xE1pido aos Shoppings";
26226
+ const themeConfig = this.getThemeConfig();
26227
+ const shortcutsTitleColor = themeConfig.shortcutsTitleColor ?? themeConfig.mutedTextColor;
26228
+ if (!shortcutsSection && modalContainer) {
26229
+ shortcutsSection = document.createElement("div");
26230
+ shortcutsSection.className = "myio-welcome-shortcuts";
26231
+ modalContainer.appendChild(shortcutsSection);
26232
+ }
26233
+ if (shortcutsSection) {
26234
+ shortcutsSection.innerHTML = `
26235
+ <h2 class="myio-welcome-shortcuts-title"${shortcutsTitleColor ? ` style="color: ${shortcutsTitleColor}"` : ""}>${shortcutsTitle}</h2>
26236
+ <div class="myio-welcome-cards-grid" id="welcomeCardsGrid">
26237
+ ${cards.map((card, index) => this.buildCardHTML(card, index)).join("")}
26238
+ </div>
26239
+ `;
26240
+ this.bindCardEvents();
26241
+ this.setupLazyLoading();
26242
+ }
26243
+ if (this.config.enableDebugMode) {
26244
+ console.log("[WelcomeModal] Shopping cards updated:", cards.length);
26245
+ }
26246
+ }
26247
+ /**
26248
+ * Bind events for shopping cards (used after dynamic update)
26249
+ */
26250
+ bindCardEvents() {
26251
+ const cards = this.container.querySelectorAll(".myio-welcome-card");
26252
+ cards.forEach((card, index) => {
26253
+ const shoppingCard = this.params.shoppingCards?.[index];
26254
+ if (!shoppingCard) return;
26255
+ card.addEventListener("click", (e) => {
26256
+ const target = e.target;
26257
+ if (target.closest(".myio-welcome-card-device-count")) {
26258
+ return;
26259
+ }
26260
+ this.emit("card-click", shoppingCard);
26261
+ });
26262
+ card.addEventListener("keydown", (e) => {
26263
+ const keyEvent = e;
26264
+ if (keyEvent.key === "Enter" || keyEvent.key === " ") {
26265
+ e.preventDefault();
26266
+ this.emit("card-click", shoppingCard);
26267
+ }
26268
+ });
26269
+ });
26270
+ this.bindTooltipEvents();
26271
+ }
26272
+ /**
26273
+ * Set CTA button label
26274
+ */
26275
+ setCtaLabel(label) {
26276
+ const ctaBtn = this.container.querySelector("#welcomeCtaBtn");
26277
+ if (ctaBtn) {
26278
+ const svgIcon = ctaBtn.querySelector("svg");
26279
+ ctaBtn.textContent = "";
26280
+ ctaBtn.appendChild(document.createTextNode(label + " "));
26281
+ if (svgIcon) {
26282
+ ctaBtn.appendChild(svgIcon);
26283
+ } else {
26284
+ const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
26285
+ svg.setAttribute("viewBox", "0 0 24 24");
26286
+ svg.setAttribute("fill", "none");
26287
+ svg.setAttribute("stroke", "currentColor");
26288
+ svg.setAttribute("stroke-width", "2");
26289
+ svg.setAttribute("stroke-linecap", "round");
26290
+ svg.setAttribute("stroke-linejoin", "round");
26291
+ svg.innerHTML = '<line x1="5" y1="12" x2="19" y2="12" /><polyline points="12 5 19 12 12 19" />';
26292
+ ctaBtn.appendChild(svg);
26293
+ }
26294
+ }
26295
+ }
26296
+ /**
26297
+ * Set CTA button disabled state
26298
+ */
26299
+ setCtaDisabled(disabled) {
26300
+ const ctaBtn = this.container.querySelector("#welcomeCtaBtn");
26301
+ if (ctaBtn) {
26302
+ ctaBtn.disabled = disabled;
26303
+ ctaBtn.style.opacity = disabled ? "0.5" : "1";
26304
+ ctaBtn.style.cursor = disabled ? "not-allowed" : "pointer";
26305
+ }
26306
+ }
26307
+ /**
26308
+ * Show the modal (after it was hidden)
26309
+ */
26310
+ show() {
26311
+ this.container.style.display = "flex";
26312
+ this.container.style.opacity = "0";
26313
+ requestAnimationFrame(() => {
26314
+ this.container.style.opacity = "1";
26315
+ this.container.style.transition = "opacity 0.3s ease";
26316
+ });
26317
+ document.body.style.overflow = "hidden";
26318
+ }
26319
+ /**
26320
+ * Hide the modal (without destroying it)
26321
+ */
26322
+ hide() {
26323
+ this.container.style.opacity = "0";
26324
+ this.container.style.transition = "opacity 0.3s ease";
26325
+ setTimeout(() => {
26326
+ this.container.style.display = "none";
26327
+ document.body.style.overflow = "";
26328
+ }, 300);
26329
+ }
26200
26330
  /**
26201
26331
  * Cleanup resources
26202
26332
  */
@@ -26317,8 +26447,15 @@ function openWelcomeModal(params) {
26317
26447
  element.style.opacity = "1";
26318
26448
  element.style.transition = "opacity 0.3s ease";
26319
26449
  });
26450
+ function open() {
26451
+ if (!element.parentNode) {
26452
+ document.body.appendChild(element);
26453
+ }
26454
+ view.show();
26455
+ }
26320
26456
  return {
26321
26457
  close,
26458
+ open,
26322
26459
  element,
26323
26460
  on: (event, handler) => {
26324
26461
  if (event === "close") {
@@ -26328,7 +26465,15 @@ function openWelcomeModal(params) {
26328
26465
  /** Set the theme mode from outside (e.g., from MAIN component) */
26329
26466
  setThemeMode: (mode) => view.setThemeMode(mode),
26330
26467
  /** Get the current theme mode */
26331
- getThemeMode: () => view.getThemeMode()
26468
+ getThemeMode: () => view.getThemeMode(),
26469
+ /** Update shopping cards after data loads (RFC-0111: loading state) */
26470
+ updateShoppingCards: (cards) => view.updateShoppingCards(cards),
26471
+ /** Update user info display */
26472
+ updateUserInfo: (info) => view.updateUserInfo(info),
26473
+ /** Set CTA button label */
26474
+ setCtaLabel: (label) => view.setCtaLabel(label),
26475
+ /** Set CTA button disabled state */
26476
+ setCtaDisabled: (disabled) => view.setCtaDisabled(disabled)
26332
26477
  };
26333
26478
  }
26334
26479