myio-js-library 0.1.197 → 0.1.199

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.js CHANGED
@@ -8875,8 +8875,8 @@ function getStatusDotClass(deviceStatus) {
8875
8875
  return "dot--offline";
8876
8876
  }
8877
8877
  }
8878
- function buildDOM(state5) {
8879
- const { entityObject, i18n, enableSelection, enableDragDrop } = state5;
8878
+ function buildDOM(state6) {
8879
+ const { entityObject, i18n, enableSelection, enableDragDrop } = state6;
8880
8880
  const root = document.createElement("div");
8881
8881
  root.className = "myio-ho-card";
8882
8882
  root.setAttribute("role", "group");
@@ -9032,7 +9032,7 @@ function buildDOM(state5) {
9032
9032
  return root;
9033
9033
  }
9034
9034
  function buildDebugTooltipInfo(entityObject, statusInfo, stateClass, statusDecisionSource, delayTimeConnectionInMins) {
9035
- const formatTimestamp5 = (ts) => {
9035
+ const formatTimestamp6 = (ts) => {
9036
9036
  if (!ts) return "N/A";
9037
9037
  const d = new Date(ts);
9038
9038
  return d.toLocaleString("pt-BR", {
@@ -9059,8 +9059,8 @@ function buildDebugTooltipInfo(entityObject, statusInfo, stateClass, statusDecis
9059
9059
  chipClass: statusInfo.chipClass,
9060
9060
  chipLabel: statusInfo.label,
9061
9061
  // Connection timestamps
9062
- lastConnectTime: formatTimestamp5(entityObject.lastConnectTime),
9063
- lastDisconnectTime: formatTimestamp5(entityObject.lastDisconnectTime),
9062
+ lastConnectTime: formatTimestamp6(entityObject.lastConnectTime),
9063
+ lastDisconnectTime: formatTimestamp6(entityObject.lastDisconnectTime),
9064
9064
  delayTimeConnectionInMins,
9065
9065
  // Raw values
9066
9066
  val: entityObject.val,
@@ -9202,8 +9202,8 @@ function verifyOfflineStatus(entityObject, delayTimeInMins = 15, LogHelper2) {
9202
9202
  }
9203
9203
  return isOffline;
9204
9204
  }
9205
- function paint(root, state5) {
9206
- const { entityObject, i18n, delayTimeConnectionInMins, isSelected, LogHelper: LogHelper2, activeTooltipDebug } = state5;
9205
+ function paint(root, state6) {
9206
+ const { entityObject, i18n, delayTimeConnectionInMins, isSelected, LogHelper: LogHelper2, activeTooltipDebug } = state6;
9207
9207
  let statusDecisionSource = "unknown";
9208
9208
  if (entityObject.connectionStatus) {
9209
9209
  if (entityObject.connectionStatus === "offline") {
@@ -9255,7 +9255,7 @@ function paint(root, state5) {
9255
9255
  numSpan.textContent = primaryValue;
9256
9256
  const barContainer = root.querySelector(".bar");
9257
9257
  const effContainer = root.querySelector(".myio-ho-card__eff");
9258
- if (state5.enableSelection) {
9258
+ if (state6.enableSelection) {
9259
9259
  const checkbox = root.querySelector('.myio-ho-card__select input[type="checkbox"]');
9260
9260
  if (checkbox) {
9261
9261
  checkbox.checked = !!isSelected;
@@ -9303,8 +9303,8 @@ function paint(root, state5) {
9303
9303
  statusDot.className = `status-dot ${dotClass}`;
9304
9304
  }
9305
9305
  }
9306
- function bindEvents(root, state5, callbacks) {
9307
- const { entityObject } = state5;
9306
+ function bindEvents(root, state6, callbacks) {
9307
+ const { entityObject } = state6;
9308
9308
  const kebabBtn = root.querySelector(".myio-ho-card__kebab");
9309
9309
  const menu = root.querySelector(".myio-ho-card__menu");
9310
9310
  function toggleMenu() {
@@ -9360,9 +9360,9 @@ function bindEvents(root, state5, callbacks) {
9360
9360
  const onSelectionChange = () => {
9361
9361
  const selectedIds = MyIOSelectionStore2.getSelectedIds();
9362
9362
  const isSelected = selectedIds.includes(entityObject.entityId);
9363
- if (state5.isSelected !== isSelected) {
9364
- state5.isSelected = isSelected;
9365
- paint(root, state5);
9363
+ if (state6.isSelected !== isSelected) {
9364
+ state6.isSelected = isSelected;
9365
+ paint(root, state6);
9366
9366
  }
9367
9367
  };
9368
9368
  MyIOSelectionStore2.on("selection:change", onSelectionChange);
@@ -9375,7 +9375,7 @@ function bindEvents(root, state5, callbacks) {
9375
9375
  clearTimeout(TempRangeTooltip._hideTimer);
9376
9376
  TempRangeTooltip._hideTimer = null;
9377
9377
  }
9378
- TempRangeTooltip.show(root, state5.entityObject, e);
9378
+ TempRangeTooltip.show(root, state6.entityObject, e);
9379
9379
  };
9380
9380
  const hideTooltip = () => {
9381
9381
  TempRangeTooltip._startDelayedHide();
@@ -9393,7 +9393,7 @@ function bindEvents(root, state5, callbacks) {
9393
9393
  clearTimeout(EnergyRangeTooltip._hideTimer);
9394
9394
  EnergyRangeTooltip._hideTimer = null;
9395
9395
  }
9396
- EnergyRangeTooltip.show(root, state5.entityObject, e);
9396
+ EnergyRangeTooltip.show(root, state6.entityObject, e);
9397
9397
  };
9398
9398
  const hideEnergyTooltip = () => {
9399
9399
  EnergyRangeTooltip._startDelayedHide();
@@ -9445,7 +9445,7 @@ function bindEvents(root, state5, callbacks) {
9445
9445
  }
9446
9446
  });
9447
9447
  }
9448
- if (state5.enableDragDrop) {
9448
+ if (state6.enableDragDrop) {
9449
9449
  root.addEventListener("dragstart", (e) => {
9450
9450
  root.classList.add("is-dragging");
9451
9451
  e.dataTransfer.setData("text/plain", entityObject.entityId);
@@ -9487,17 +9487,17 @@ function renderCardComponentHeadOffice(containerEl, params) {
9487
9487
  throw new Error("renderCardComponentHeadOffice: containerEl is required");
9488
9488
  }
9489
9489
  ensureCss();
9490
- const state5 = normalizeParams(params);
9491
- const root = buildDOM(state5);
9492
- state5.isSelected = params.isSelected || false;
9490
+ const state6 = normalizeParams(params);
9491
+ const root = buildDOM(state6);
9492
+ state6.isSelected = params.isSelected || false;
9493
9493
  containerEl.appendChild(root);
9494
- bindEvents(root, state5, state5.callbacks);
9495
- paint(root, state5);
9494
+ bindEvents(root, state6, state6.callbacks);
9495
+ paint(root, state6);
9496
9496
  return {
9497
9497
  update(next) {
9498
9498
  if (next) {
9499
- Object.assign(state5.entityObject, next);
9500
- paint(root, state5);
9499
+ Object.assign(state6.entityObject, next);
9500
+ paint(root, state6);
9501
9501
  }
9502
9502
  },
9503
9503
  destroy() {
@@ -11227,6 +11227,15 @@ function calculateTempStatus(currentTemp, avgTemp) {
11227
11227
  return { deviation: absDeviation, sign: "-", status: "below", statusText: "Abaixo da media", statusIcon: "\u{1F53B}" };
11228
11228
  }
11229
11229
  }
11230
+ function calculateRangeStatus(currentTemp, minTemp, maxTemp) {
11231
+ if (currentTemp >= minTemp && currentTemp <= maxTemp) {
11232
+ return { status: "ok", statusText: "Dentro da faixa", statusIcon: "\u2713" };
11233
+ } else if (currentTemp > maxTemp) {
11234
+ return { status: "above", statusText: "Acima da faixa", statusIcon: "\u{1F53A}" };
11235
+ } else {
11236
+ return { status: "below", statusText: "Abaixo da faixa", statusIcon: "\u{1F53B}" };
11237
+ }
11238
+ }
11230
11239
  function calcTempBarPosition(temp, minRange, maxRange) {
11231
11240
  const rangeSize = maxRange - minRange;
11232
11241
  const extendedMin = minRange - rangeSize * 0.3;
@@ -11269,8 +11278,10 @@ function generateBodyHTML2(data) {
11269
11278
  const { device, average, lastUpdated } = data;
11270
11279
  const timestamp = formatTimestamp2(lastUpdated);
11271
11280
  const tempStatus = calculateTempStatus(device.currentTemp, average.value);
11281
+ const rangeStatus = calculateRangeStatus(device.currentTemp, device.minTemp, device.maxTemp);
11272
11282
  const deviceBarPos = calcTempBarPosition(device.currentTemp, device.minTemp, device.maxTemp);
11273
11283
  const avgBarPos = calcTempBarPosition(average.value, device.minTemp, device.maxTemp);
11284
+ const rangeStatusClass = rangeStatus.status === "ok" ? "normal" : rangeStatus.status;
11274
11285
  return `
11275
11286
  <div class="myio-temp-comparison-tooltip__body">
11276
11287
  <!-- Main Stats -->
@@ -11285,12 +11296,18 @@ function generateBodyHTML2(data) {
11285
11296
  </div>
11286
11297
  </div>
11287
11298
 
11288
- <!-- Configured Range -->
11299
+ <!-- Configured Range with Status -->
11289
11300
  <div class="myio-temp-comparison-tooltip__range">
11290
11301
  <span class="myio-temp-comparison-tooltip__range-label">Faixa Ideal:</span>
11291
11302
  <span class="myio-temp-comparison-tooltip__range-value">${formatTemp(device.minTemp)} - ${formatTemp(device.maxTemp)}</span>
11292
11303
  </div>
11293
11304
 
11305
+ <!-- Range Status Indicator -->
11306
+ <div class="myio-temp-comparison-tooltip__status ${rangeStatusClass}">
11307
+ <span class="myio-temp-comparison-tooltip__status-icon">${rangeStatus.statusIcon}</span>
11308
+ <span>${rangeStatus.statusText}</span>
11309
+ </div>
11310
+
11294
11311
  <!-- Section: Average Comparison -->
11295
11312
  <div class="myio-temp-comparison-tooltip__section-title">
11296
11313
  <span class="myio-temp-comparison-tooltip__section-icon">\u{1F4CA}</span>
@@ -30800,7 +30817,7 @@ async function openTemperatureModal(params) {
30800
30817
  const defaultDateRange = getTodaySoFar();
30801
30818
  const startTs = params.startDate ? new Date(params.startDate).getTime() : defaultDateRange.startTs;
30802
30819
  const endTs = params.endDate ? new Date(params.endDate).getTime() : defaultDateRange.endTs;
30803
- const state5 = {
30820
+ const state6 = {
30804
30821
  token: params.token,
30805
30822
  deviceId: params.deviceId,
30806
30823
  label: params.label || "Sensor de Temperatura",
@@ -30823,58 +30840,58 @@ async function openTemperatureModal(params) {
30823
30840
  };
30824
30841
  const savedGranularity = localStorage.getItem("myio-temp-modal-granularity");
30825
30842
  const savedTheme = localStorage.getItem("myio-temp-modal-theme");
30826
- if (savedGranularity) state5.granularity = savedGranularity;
30827
- if (savedTheme) state5.theme = savedTheme;
30843
+ if (savedGranularity) state6.granularity = savedGranularity;
30844
+ if (savedTheme) state6.theme = savedTheme;
30828
30845
  const modalContainer = document.createElement("div");
30829
30846
  modalContainer.id = modalId;
30830
30847
  document.body.appendChild(modalContainer);
30831
- renderModal(modalContainer, state5, modalId);
30848
+ renderModal(modalContainer, state6, modalId);
30832
30849
  try {
30833
- state5.data = await fetchTemperatureData(state5.token, state5.deviceId, state5.startTs, state5.endTs);
30834
- state5.stats = calculateStats(state5.data, state5.clampRange);
30835
- state5.isLoading = false;
30836
- renderModal(modalContainer, state5, modalId);
30837
- drawChart(modalId, state5);
30850
+ state6.data = await fetchTemperatureData(state6.token, state6.deviceId, state6.startTs, state6.endTs);
30851
+ state6.stats = calculateStats(state6.data, state6.clampRange);
30852
+ state6.isLoading = false;
30853
+ renderModal(modalContainer, state6, modalId);
30854
+ drawChart(modalId, state6);
30838
30855
  } catch (error) {
30839
30856
  console.error("[TemperatureModal] Error fetching data:", error);
30840
- state5.isLoading = false;
30841
- renderModal(modalContainer, state5, modalId, error);
30857
+ state6.isLoading = false;
30858
+ renderModal(modalContainer, state6, modalId, error);
30842
30859
  }
30843
- await setupEventListeners(modalContainer, state5, modalId, params.onClose);
30860
+ await setupEventListeners(modalContainer, state6, modalId, params.onClose);
30844
30861
  return {
30845
30862
  destroy: () => {
30846
30863
  modalContainer.remove();
30847
30864
  params.onClose?.();
30848
30865
  },
30849
30866
  updateData: async (startDate, endDate, granularity) => {
30850
- state5.startTs = new Date(startDate).getTime();
30851
- state5.endTs = new Date(endDate).getTime();
30852
- if (granularity) state5.granularity = granularity;
30853
- state5.isLoading = true;
30854
- renderModal(modalContainer, state5, modalId);
30867
+ state6.startTs = new Date(startDate).getTime();
30868
+ state6.endTs = new Date(endDate).getTime();
30869
+ if (granularity) state6.granularity = granularity;
30870
+ state6.isLoading = true;
30871
+ renderModal(modalContainer, state6, modalId);
30855
30872
  try {
30856
- state5.data = await fetchTemperatureData(state5.token, state5.deviceId, state5.startTs, state5.endTs);
30857
- state5.stats = calculateStats(state5.data, state5.clampRange);
30858
- state5.isLoading = false;
30859
- renderModal(modalContainer, state5, modalId);
30860
- drawChart(modalId, state5);
30873
+ state6.data = await fetchTemperatureData(state6.token, state6.deviceId, state6.startTs, state6.endTs);
30874
+ state6.stats = calculateStats(state6.data, state6.clampRange);
30875
+ state6.isLoading = false;
30876
+ renderModal(modalContainer, state6, modalId);
30877
+ drawChart(modalId, state6);
30861
30878
  } catch (error) {
30862
30879
  console.error("[TemperatureModal] Error updating data:", error);
30863
- state5.isLoading = false;
30864
- renderModal(modalContainer, state5, modalId, error);
30880
+ state6.isLoading = false;
30881
+ renderModal(modalContainer, state6, modalId, error);
30865
30882
  }
30866
30883
  }
30867
30884
  };
30868
30885
  }
30869
- function renderModal(container, state5, modalId, error) {
30870
- const colors = getThemeColors(state5.theme);
30871
- const startDateStr = new Date(state5.startTs).toLocaleDateString(state5.locale);
30872
- const endDateStr = new Date(state5.endTs).toLocaleDateString(state5.locale);
30873
- const statusText = state5.temperatureStatus === "ok" ? "Dentro da faixa" : state5.temperatureStatus === "above" ? "Acima do limite" : state5.temperatureStatus === "below" ? "Abaixo do limite" : "N/A";
30874
- const statusColor = state5.temperatureStatus === "ok" ? colors.success : state5.temperatureStatus === "above" ? colors.danger : state5.temperatureStatus === "below" ? colors.primary : colors.textMuted;
30875
- const rangeText = state5.temperatureMin !== null && state5.temperatureMax !== null ? `${state5.temperatureMin}\xB0C - ${state5.temperatureMax}\xB0C` : "N\xE3o definida";
30876
- const startDateInput = new Date(state5.startTs).toISOString().slice(0, 16);
30877
- const endDateInput = new Date(state5.endTs).toISOString().slice(0, 16);
30886
+ function renderModal(container, state6, modalId, error) {
30887
+ const colors = getThemeColors(state6.theme);
30888
+ const startDateStr = new Date(state6.startTs).toLocaleDateString(state6.locale);
30889
+ const endDateStr = new Date(state6.endTs).toLocaleDateString(state6.locale);
30890
+ const statusText = state6.temperatureStatus === "ok" ? "Dentro da faixa" : state6.temperatureStatus === "above" ? "Acima do limite" : state6.temperatureStatus === "below" ? "Abaixo do limite" : "N/A";
30891
+ const statusColor = state6.temperatureStatus === "ok" ? colors.success : state6.temperatureStatus === "above" ? colors.danger : state6.temperatureStatus === "below" ? colors.primary : colors.textMuted;
30892
+ const rangeText = state6.temperatureMin !== null && state6.temperatureMax !== null ? `${state6.temperatureMin}\xB0C - ${state6.temperatureMax}\xB0C` : "N\xE3o definida";
30893
+ const startDateInput = new Date(state6.startTs).toISOString().slice(0, 16);
30894
+ const endDateInput = new Date(state6.endTs).toISOString().slice(0, 16);
30878
30895
  const isMaximized = container.__isMaximized || false;
30879
30896
  const contentMaxWidth = isMaximized ? "100%" : "900px";
30880
30897
  const contentMaxHeight = isMaximized ? "100vh" : "95vh";
@@ -30901,7 +30918,7 @@ function renderModal(container, state5, modalId, error) {
30901
30918
  min-height: 20px;
30902
30919
  ">
30903
30920
  <h2 style="margin: 6px; font-size: 18px; font-weight: 600; color: white; line-height: 2;">
30904
- \u{1F321}\uFE0F ${state5.label} - Hist\xF3rico de Temperatura
30921
+ \u{1F321}\uFE0F ${state6.label} - Hist\xF3rico de Temperatura
30905
30922
  </h2>
30906
30923
  <div style="display: flex; gap: 4px; align-items: center;">
30907
30924
  <!-- Theme Toggle -->
@@ -30909,7 +30926,7 @@ function renderModal(container, state5, modalId, error) {
30909
30926
  background: none; border: none; font-size: 16px; cursor: pointer;
30910
30927
  padding: 4px 8px; border-radius: 6px; color: rgba(255,255,255,0.8);
30911
30928
  transition: background-color 0.2s;
30912
- ">${state5.theme === "dark" ? "\u2600\uFE0F" : "\u{1F319}"}</button>
30929
+ ">${state6.theme === "dark" ? "\u2600\uFE0F" : "\u{1F319}"}</button>
30913
30930
  <!-- Maximize Button -->
30914
30931
  <button id="${modalId}-maximize" title="${isMaximized ? "Restaurar" : "Maximizar"}" style="
30915
30932
  background: none; border: none; font-size: 16px; cursor: pointer;
@@ -30931,7 +30948,7 @@ function renderModal(container, state5, modalId, error) {
30931
30948
  <!-- Controls Row -->
30932
30949
  <div style="
30933
30950
  display: flex; gap: 16px; flex-wrap: wrap; align-items: flex-end;
30934
- margin-bottom: 16px; padding: 16px; background: ${state5.theme === "dark" ? "rgba(255,255,255,0.05)" : "#f7f7f7"};
30951
+ margin-bottom: 16px; padding: 16px; background: ${state6.theme === "dark" ? "rgba(255,255,255,0.05)" : "#f7f7f7"};
30935
30952
  border-radius: 6px; border: 1px solid ${colors.border};
30936
30953
  ">
30937
30954
  <!-- Granularity Select -->
@@ -30944,8 +30961,8 @@ function renderModal(container, state5, modalId, error) {
30944
30961
  font-size: 14px; color: ${colors.text}; background: ${colors.surface};
30945
30962
  cursor: pointer; min-width: 130px;
30946
30963
  ">
30947
- <option value="hour" ${state5.granularity === "hour" ? "selected" : ""}>Hora (30 min)</option>
30948
- <option value="day" ${state5.granularity === "day" ? "selected" : ""}>Dia (m\xE9dia)</option>
30964
+ <option value="hour" ${state6.granularity === "hour" ? "selected" : ""}>Hora (30 min)</option>
30965
+ <option value="day" ${state6.granularity === "day" ? "selected" : ""}>Dia (m\xE9dia)</option>
30949
30966
  </select>
30950
30967
  </div>
30951
30968
  <!-- Day Period Filter (Multiselect) -->
@@ -30959,7 +30976,7 @@ function renderModal(container, state5, modalId, error) {
30959
30976
  cursor: pointer; min-width: 180px; text-align: left;
30960
30977
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
30961
30978
  ">
30962
- <span>${getSelectedPeriodsLabel(state5.selectedPeriods)}</span>
30979
+ <span>${getSelectedPeriodsLabel(state6.selectedPeriods)}</span>
30963
30980
  <span style="font-size: 10px;">\u25BC</span>
30964
30981
  </button>
30965
30982
  <div id="${modalId}-period-dropdown" style="
@@ -30972,12 +30989,12 @@ function renderModal(container, state5, modalId, error) {
30972
30989
  <label style="
30973
30990
  display: flex; align-items: center; gap: 8px; padding: 8px 12px;
30974
30991
  cursor: pointer; font-size: 13px; color: ${colors.text};
30975
- " onmouseover="this.style.background='${state5.theme === "dark" ? "rgba(255,255,255,0.1)" : "#f0f0f0"}'"
30992
+ " onmouseover="this.style.background='${state6.theme === "dark" ? "rgba(255,255,255,0.1)" : "#f0f0f0"}'"
30976
30993
  onmouseout="this.style.background='transparent'">
30977
30994
  <input type="checkbox"
30978
30995
  name="${modalId}-period"
30979
30996
  value="${period.id}"
30980
- ${state5.selectedPeriods.includes(period.id) ? "checked" : ""}
30997
+ ${state6.selectedPeriods.includes(period.id) ? "checked" : ""}
30981
30998
  style="width: 16px; height: 16px; cursor: pointer; accent-color: #3e1a7d;">
30982
30999
  ${period.label}
30983
31000
  </label>
@@ -30985,13 +31002,13 @@ function renderModal(container, state5, modalId, error) {
30985
31002
  <div style="border-top: 1px solid ${colors.border}; margin-top: 8px; padding-top: 8px;">
30986
31003
  <button id="${modalId}-period-select-all" type="button" style="
30987
31004
  width: calc(100% - 16px); margin: 0 8px 4px; padding: 6px;
30988
- background: ${state5.theme === "dark" ? "rgba(255,255,255,0.1)" : "#f0f0f0"};
31005
+ background: ${state6.theme === "dark" ? "rgba(255,255,255,0.1)" : "#f0f0f0"};
30989
31006
  border: none; border-radius: 4px; cursor: pointer;
30990
31007
  font-size: 12px; color: ${colors.text};
30991
31008
  ">Selecionar Todos</button>
30992
31009
  <button id="${modalId}-period-clear" type="button" style="
30993
31010
  width: calc(100% - 16px); margin: 0 8px; padding: 6px;
30994
- background: ${state5.theme === "dark" ? "rgba(255,255,255,0.1)" : "#f0f0f0"};
31011
+ background: ${state6.theme === "dark" ? "rgba(255,255,255,0.1)" : "#f0f0f0"};
30995
31012
  border: none; border-radius: 4px; cursor: pointer;
30996
31013
  font-size: 12px; color: ${colors.text};
30997
31014
  ">Limpar Sele\xE7\xE3o</button>
@@ -31016,8 +31033,8 @@ function renderModal(container, state5, modalId, error) {
31016
31033
  font-size: 14px; font-weight: 500; height: 38px;
31017
31034
  display: flex; align-items: center; gap: 8px;
31018
31035
  font-family: 'Roboto', Arial, sans-serif;
31019
- " ${state5.isLoading ? "disabled" : ""}>
31020
- ${state5.isLoading ? '<span style="animation: spin 1s linear infinite; display: inline-block;">\u21BB</span> Carregando...' : "Carregar"}
31036
+ " ${state6.isLoading ? "disabled" : ""}>
31037
+ ${state6.isLoading ? '<span style="animation: spin 1s linear infinite; display: inline-block;">\u21BB</span> Carregando...' : "Carregar"}
31021
31038
  </button>
31022
31039
  </div>
31023
31040
 
@@ -31028,40 +31045,40 @@ function renderModal(container, state5, modalId, error) {
31028
31045
  ">
31029
31046
  <!-- Current Temperature -->
31030
31047
  <div style="
31031
- padding: 16px; background: ${state5.theme === "dark" ? "rgba(255,255,255,0.05)" : "#fafafa"};
31048
+ padding: 16px; background: ${state6.theme === "dark" ? "rgba(255,255,255,0.05)" : "#fafafa"};
31032
31049
  border-radius: 12px; border: 1px solid ${colors.border};
31033
31050
  ">
31034
31051
  <span style="color: ${colors.textMuted}; font-size: 12px; font-weight: 500;">Temperatura Atual</span>
31035
31052
  <div style="font-weight: 700; font-size: 24px; color: ${statusColor}; margin-top: 4px;">
31036
- ${state5.currentTemperature !== null ? formatTemperature(state5.currentTemperature) : "N/A"}
31053
+ ${state6.currentTemperature !== null ? formatTemperature(state6.currentTemperature) : "N/A"}
31037
31054
  </div>
31038
31055
  <div style="font-size: 11px; color: ${statusColor}; margin-top: 2px;">${statusText}</div>
31039
31056
  </div>
31040
31057
  <!-- Average -->
31041
31058
  <div style="
31042
- padding: 16px; background: ${state5.theme === "dark" ? "rgba(255,255,255,0.05)" : "#fafafa"};
31059
+ padding: 16px; background: ${state6.theme === "dark" ? "rgba(255,255,255,0.05)" : "#fafafa"};
31043
31060
  border-radius: 12px; border: 1px solid ${colors.border};
31044
31061
  ">
31045
31062
  <span style="color: ${colors.textMuted}; font-size: 12px; font-weight: 500;">M\xE9dia do Per\xEDodo</span>
31046
31063
  <div id="${modalId}-avg" style="font-weight: 600; font-size: 20px; color: ${colors.text}; margin-top: 4px;">
31047
- ${state5.stats.count > 0 ? formatTemperature(state5.stats.avg) : "N/A"}
31064
+ ${state6.stats.count > 0 ? formatTemperature(state6.stats.avg) : "N/A"}
31048
31065
  </div>
31049
31066
  <div style="font-size: 11px; color: ${colors.textMuted}; margin-top: 2px;">${startDateStr} - ${endDateStr}</div>
31050
31067
  </div>
31051
31068
  <!-- Min/Max -->
31052
31069
  <div style="
31053
- padding: 16px; background: ${state5.theme === "dark" ? "rgba(255,255,255,0.05)" : "#fafafa"};
31070
+ padding: 16px; background: ${state6.theme === "dark" ? "rgba(255,255,255,0.05)" : "#fafafa"};
31054
31071
  border-radius: 12px; border: 1px solid ${colors.border};
31055
31072
  ">
31056
31073
  <span style="color: ${colors.textMuted}; font-size: 12px; font-weight: 500;">Min / Max</span>
31057
31074
  <div id="${modalId}-minmax" style="font-weight: 600; font-size: 20px; color: ${colors.text}; margin-top: 4px;">
31058
- ${state5.stats.count > 0 ? `${formatTemperature(state5.stats.min)} / ${formatTemperature(state5.stats.max)}` : "N/A"}
31075
+ ${state6.stats.count > 0 ? `${formatTemperature(state6.stats.min)} / ${formatTemperature(state6.stats.max)}` : "N/A"}
31059
31076
  </div>
31060
- <div style="font-size: 11px; color: ${colors.textMuted}; margin-top: 2px;">${state5.stats.count} leituras</div>
31077
+ <div style="font-size: 11px; color: ${colors.textMuted}; margin-top: 2px;">${state6.stats.count} leituras</div>
31061
31078
  </div>
31062
31079
  <!-- Ideal Range -->
31063
31080
  <div style="
31064
- padding: 16px; background: ${state5.theme === "dark" ? "rgba(255,255,255,0.05)" : "#fafafa"};
31081
+ padding: 16px; background: ${state6.theme === "dark" ? "rgba(255,255,255,0.05)" : "#fafafa"};
31065
31082
  border-radius: 12px; border: 1px solid ${colors.border};
31066
31083
  ">
31067
31084
  <span style="color: ${colors.textMuted}; font-size: 12px; font-weight: 500;">Faixa Ideal</span>
@@ -31077,18 +31094,18 @@ function renderModal(container, state5, modalId, error) {
31077
31094
  Hist\xF3rico de Temperatura
31078
31095
  </h3>
31079
31096
  <div id="${modalId}-chart" style="
31080
- height: 320px; background: ${state5.theme === "dark" ? "rgba(255,255,255,0.03)" : "#fafafa"};
31097
+ height: 320px; background: ${state6.theme === "dark" ? "rgba(255,255,255,0.03)" : "#fafafa"};
31081
31098
  border-radius: 12px; display: flex; justify-content: center; align-items: center;
31082
31099
  border: 1px solid ${colors.border}; position: relative;
31083
31100
  ">
31084
- ${state5.isLoading ? `<div style="text-align: center; color: ${colors.textMuted};">
31101
+ ${state6.isLoading ? `<div style="text-align: center; color: ${colors.textMuted};">
31085
31102
  <div style="animation: spin 1s linear infinite; font-size: 32px; margin-bottom: 8px;">\u21BB</div>
31086
31103
  <div>Carregando dados...</div>
31087
31104
  </div>` : error ? `<div style="text-align: center; color: ${colors.danger};">
31088
31105
  <div style="font-size: 32px; margin-bottom: 8px;">\u26A0\uFE0F</div>
31089
31106
  <div>Erro ao carregar dados</div>
31090
31107
  <div style="font-size: 12px; margin-top: 4px;">${error.message}</div>
31091
- </div>` : state5.data.length === 0 ? `<div style="text-align: center; color: ${colors.textMuted};">
31108
+ </div>` : state6.data.length === 0 ? `<div style="text-align: center; color: ${colors.textMuted};">
31092
31109
  <div style="font-size: 32px; margin-bottom: 8px;">\u{1F4ED}</div>
31093
31110
  <div>Sem dados para o per\xEDodo selecionado</div>
31094
31111
  </div>` : `<canvas id="${modalId}-canvas" style="width: 100%; height: 100%;"></canvas>`}
@@ -31098,12 +31115,12 @@ function renderModal(container, state5, modalId, error) {
31098
31115
  <!-- Actions -->
31099
31116
  <div style="display: flex; justify-content: flex-end; gap: 12px;">
31100
31117
  <button id="${modalId}-export" style="
31101
- background: ${state5.theme === "dark" ? "rgba(255,255,255,0.1)" : "#f7f7f7"};
31118
+ background: ${state6.theme === "dark" ? "rgba(255,255,255,0.1)" : "#f7f7f7"};
31102
31119
  color: ${colors.text}; border: 1px solid ${colors.border};
31103
31120
  padding: 8px 16px; border-radius: 6px; cursor: pointer;
31104
31121
  font-size: 14px; display: flex; align-items: center; gap: 8px;
31105
31122
  font-family: 'Roboto', Arial, sans-serif;
31106
- " ${state5.data.length === 0 ? "disabled" : ""}>
31123
+ " ${state6.data.length === 0 ? "disabled" : ""}>
31107
31124
  \u{1F4E5} Exportar CSV
31108
31125
  </button>
31109
31126
  <button id="${modalId}-close-btn" style="
@@ -31154,14 +31171,14 @@ function renderModal(container, state5, modalId, error) {
31154
31171
  </style>
31155
31172
  `;
31156
31173
  }
31157
- function drawChart(modalId, state5) {
31174
+ function drawChart(modalId, state6) {
31158
31175
  const chartContainer = document.getElementById(`${modalId}-chart`);
31159
31176
  const canvas = document.getElementById(`${modalId}-canvas`);
31160
- if (!chartContainer || !canvas || state5.data.length === 0) return;
31177
+ if (!chartContainer || !canvas || state6.data.length === 0) return;
31161
31178
  const ctx = canvas.getContext("2d");
31162
31179
  if (!ctx) return;
31163
- const colors = getThemeColors(state5.theme);
31164
- const filteredData = filterByDayPeriods(state5.data, state5.selectedPeriods);
31180
+ const colors = getThemeColors(state6.theme);
31181
+ const filteredData = filterByDayPeriods(state6.data, state6.selectedPeriods);
31165
31182
  if (filteredData.length === 0) {
31166
31183
  canvas.width = chartContainer.clientWidth;
31167
31184
  canvas.height = chartContainer.clientHeight;
@@ -31172,14 +31189,14 @@ function drawChart(modalId, state5) {
31172
31189
  return;
31173
31190
  }
31174
31191
  let chartData;
31175
- if (state5.granularity === "hour") {
31192
+ if (state6.granularity === "hour") {
31176
31193
  const interpolated = interpolateTemperature(filteredData, {
31177
31194
  intervalMinutes: 30,
31178
- startTs: state5.startTs,
31179
- endTs: state5.endTs,
31180
- clampRange: state5.clampRange
31195
+ startTs: state6.startTs,
31196
+ endTs: state6.endTs,
31197
+ clampRange: state6.clampRange
31181
31198
  });
31182
- const filteredInterpolated = filterByDayPeriods(interpolated, state5.selectedPeriods);
31199
+ const filteredInterpolated = filterByDayPeriods(interpolated, state6.selectedPeriods);
31183
31200
  chartData = filteredInterpolated.map((item) => ({
31184
31201
  x: item.ts,
31185
31202
  y: Number(item.value),
@@ -31187,7 +31204,7 @@ function drawChart(modalId, state5) {
31187
31204
  screenY: 0
31188
31205
  }));
31189
31206
  } else {
31190
- const daily = aggregateByDay(filteredData, state5.clampRange);
31207
+ const daily = aggregateByDay(filteredData, state6.clampRange);
31191
31208
  chartData = daily.map((item) => ({
31192
31209
  x: item.dateTs,
31193
31210
  y: item.avg,
@@ -31205,12 +31222,12 @@ function drawChart(modalId, state5) {
31205
31222
  const paddingRight = 20;
31206
31223
  const paddingTop = 20;
31207
31224
  const paddingBottom = 55;
31208
- const isPeriodsFiltered = state5.selectedPeriods.length < 4 && state5.selectedPeriods.length > 0;
31225
+ const isPeriodsFiltered = state6.selectedPeriods.length < 4 && state6.selectedPeriods.length > 0;
31209
31226
  const values = chartData.map((d) => d.y);
31210
31227
  const dataMin = Math.min(...values);
31211
31228
  const dataMax = Math.max(...values);
31212
- const thresholdMin = state5.temperatureMin !== null ? state5.temperatureMin : dataMin;
31213
- const thresholdMax = state5.temperatureMax !== null ? state5.temperatureMax : dataMax;
31229
+ const thresholdMin = state6.temperatureMin !== null ? state6.temperatureMin : dataMin;
31230
+ const thresholdMax = state6.temperatureMax !== null ? state6.temperatureMax : dataMax;
31214
31231
  const minY = Math.min(dataMin, thresholdMin) - 1;
31215
31232
  const maxY = Math.max(dataMax, thresholdMax) + 1;
31216
31233
  const chartWidth = width - paddingLeft - paddingRight;
@@ -31242,9 +31259,9 @@ function drawChart(modalId, state5) {
31242
31259
  ctx.lineTo(width - paddingRight, y);
31243
31260
  ctx.stroke();
31244
31261
  }
31245
- if (state5.temperatureMin !== null && state5.temperatureMax !== null) {
31246
- const rangeMinY = height - paddingBottom - (state5.temperatureMin - minY) * scaleY;
31247
- const rangeMaxY = height - paddingBottom - (state5.temperatureMax - minY) * scaleY;
31262
+ if (state6.temperatureMin !== null && state6.temperatureMax !== null) {
31263
+ const rangeMinY = height - paddingBottom - (state6.temperatureMin - minY) * scaleY;
31264
+ const rangeMaxY = height - paddingBottom - (state6.temperatureMax - minY) * scaleY;
31248
31265
  ctx.fillStyle = "rgba(76, 175, 80, 0.1)";
31249
31266
  ctx.fillRect(paddingLeft, rangeMaxY, chartWidth, rangeMinY - rangeMaxY);
31250
31267
  ctx.strokeStyle = colors.success;
@@ -31286,10 +31303,10 @@ function drawChart(modalId, state5) {
31286
31303
  const point = chartData[i];
31287
31304
  const date = new Date(point.x);
31288
31305
  let label;
31289
- if (state5.granularity === "hour") {
31290
- label = date.toLocaleTimeString(state5.locale, { hour: "2-digit", minute: "2-digit" });
31306
+ if (state6.granularity === "hour") {
31307
+ label = date.toLocaleTimeString(state6.locale, { hour: "2-digit", minute: "2-digit" });
31291
31308
  } else {
31292
- label = date.toLocaleDateString(state5.locale, { day: "2-digit", month: "2-digit" });
31309
+ label = date.toLocaleDateString(state6.locale, { day: "2-digit", month: "2-digit" });
31293
31310
  }
31294
31311
  ctx.strokeStyle = colors.chartGrid;
31295
31312
  ctx.lineWidth = 1;
@@ -31307,16 +31324,16 @@ function drawChart(modalId, state5) {
31307
31324
  ctx.lineTo(paddingLeft, height - paddingBottom);
31308
31325
  ctx.lineTo(width - paddingRight, height - paddingBottom);
31309
31326
  ctx.stroke();
31310
- setupChartTooltip(canvas, chartContainer, chartData, state5, colors);
31327
+ setupChartTooltip(canvas, chartContainer, chartData, state6, colors);
31311
31328
  }
31312
- function setupChartTooltip(canvas, container, chartData, state5, colors) {
31329
+ function setupChartTooltip(canvas, container, chartData, state6, colors) {
31313
31330
  const existingTooltip = container.querySelector(".myio-chart-tooltip");
31314
31331
  if (existingTooltip) existingTooltip.remove();
31315
31332
  const tooltip = document.createElement("div");
31316
31333
  tooltip.className = "myio-chart-tooltip";
31317
31334
  tooltip.style.cssText = `
31318
31335
  position: absolute;
31319
- background: ${state5.theme === "dark" ? "rgba(30, 30, 40, 0.95)" : "rgba(255, 255, 255, 0.98)"};
31336
+ background: ${state6.theme === "dark" ? "rgba(30, 30, 40, 0.95)" : "rgba(255, 255, 255, 0.98)"};
31320
31337
  border: 1px solid ${colors.border};
31321
31338
  border-radius: 8px;
31322
31339
  padding: 10px 14px;
@@ -31353,17 +31370,17 @@ function setupChartTooltip(canvas, container, chartData, state5, colors) {
31353
31370
  if (point) {
31354
31371
  const date = new Date(point.x);
31355
31372
  let dateStr;
31356
- if (state5.granularity === "hour") {
31357
- dateStr = date.toLocaleDateString(state5.locale, {
31373
+ if (state6.granularity === "hour") {
31374
+ dateStr = date.toLocaleDateString(state6.locale, {
31358
31375
  day: "2-digit",
31359
31376
  month: "2-digit",
31360
31377
  year: "numeric"
31361
- }) + " " + date.toLocaleTimeString(state5.locale, {
31378
+ }) + " " + date.toLocaleTimeString(state6.locale, {
31362
31379
  hour: "2-digit",
31363
31380
  minute: "2-digit"
31364
31381
  });
31365
31382
  } else {
31366
- dateStr = date.toLocaleDateString(state5.locale, {
31383
+ dateStr = date.toLocaleDateString(state6.locale, {
31367
31384
  day: "2-digit",
31368
31385
  month: "2-digit",
31369
31386
  year: "numeric"
@@ -31401,7 +31418,7 @@ function setupChartTooltip(canvas, container, chartData, state5, colors) {
31401
31418
  canvas.style.cursor = "default";
31402
31419
  });
31403
31420
  }
31404
- async function setupEventListeners(container, state5, modalId, onClose) {
31421
+ async function setupEventListeners(container, state6, modalId, onClose) {
31405
31422
  const closeModal = () => {
31406
31423
  container.remove();
31407
31424
  onClose?.();
@@ -31412,19 +31429,19 @@ async function setupEventListeners(container, state5, modalId, onClose) {
31412
31429
  document.getElementById(`${modalId}-close`)?.addEventListener("click", closeModal);
31413
31430
  document.getElementById(`${modalId}-close-btn`)?.addEventListener("click", closeModal);
31414
31431
  const dateRangeInput = document.getElementById(`${modalId}-date-range`);
31415
- if (dateRangeInput && !state5.dateRangePicker) {
31432
+ if (dateRangeInput && !state6.dateRangePicker) {
31416
31433
  try {
31417
- state5.dateRangePicker = await createDateRangePicker2(dateRangeInput, {
31418
- presetStart: new Date(state5.startTs).toISOString(),
31419
- presetEnd: new Date(state5.endTs).toISOString(),
31434
+ state6.dateRangePicker = await createDateRangePicker2(dateRangeInput, {
31435
+ presetStart: new Date(state6.startTs).toISOString(),
31436
+ presetEnd: new Date(state6.endTs).toISOString(),
31420
31437
  includeTime: true,
31421
31438
  timePrecision: "minute",
31422
31439
  maxRangeDays: 90,
31423
- locale: state5.locale,
31440
+ locale: state6.locale,
31424
31441
  parentEl: container.querySelector(".myio-temp-modal-content"),
31425
31442
  onApply: (result) => {
31426
- state5.startTs = new Date(result.startISO).getTime();
31427
- state5.endTs = new Date(result.endISO).getTime();
31443
+ state6.startTs = new Date(result.startISO).getTime();
31444
+ state6.endTs = new Date(result.endISO).getTime();
31428
31445
  console.log("[TemperatureModal] Date range applied:", result);
31429
31446
  }
31430
31447
  });
@@ -31433,19 +31450,19 @@ async function setupEventListeners(container, state5, modalId, onClose) {
31433
31450
  }
31434
31451
  }
31435
31452
  document.getElementById(`${modalId}-theme-toggle`)?.addEventListener("click", async () => {
31436
- state5.theme = state5.theme === "dark" ? "light" : "dark";
31437
- localStorage.setItem("myio-temp-modal-theme", state5.theme);
31438
- state5.dateRangePicker = null;
31439
- renderModal(container, state5, modalId);
31440
- if (state5.data.length > 0) drawChart(modalId, state5);
31441
- await setupEventListeners(container, state5, modalId, onClose);
31453
+ state6.theme = state6.theme === "dark" ? "light" : "dark";
31454
+ localStorage.setItem("myio-temp-modal-theme", state6.theme);
31455
+ state6.dateRangePicker = null;
31456
+ renderModal(container, state6, modalId);
31457
+ if (state6.data.length > 0) drawChart(modalId, state6);
31458
+ await setupEventListeners(container, state6, modalId, onClose);
31442
31459
  });
31443
31460
  document.getElementById(`${modalId}-maximize`)?.addEventListener("click", async () => {
31444
31461
  container.__isMaximized = !container.__isMaximized;
31445
- state5.dateRangePicker = null;
31446
- renderModal(container, state5, modalId);
31447
- if (state5.data.length > 0) drawChart(modalId, state5);
31448
- await setupEventListeners(container, state5, modalId, onClose);
31462
+ state6.dateRangePicker = null;
31463
+ renderModal(container, state6, modalId);
31464
+ if (state6.data.length > 0) drawChart(modalId, state6);
31465
+ await setupEventListeners(container, state6, modalId, onClose);
31449
31466
  });
31450
31467
  const periodBtn = document.getElementById(`${modalId}-period-btn`);
31451
31468
  const periodDropdown = document.getElementById(`${modalId}-period-dropdown`);
@@ -31464,71 +31481,71 @@ async function setupEventListeners(container, state5, modalId, onClose) {
31464
31481
  periodCheckboxes.forEach((checkbox) => {
31465
31482
  checkbox.addEventListener("change", () => {
31466
31483
  const checked = Array.from(periodCheckboxes).filter((cb) => cb.checked).map((cb) => cb.value);
31467
- state5.selectedPeriods = checked;
31484
+ state6.selectedPeriods = checked;
31468
31485
  const btnLabel = periodBtn?.querySelector("span:first-child");
31469
31486
  if (btnLabel) {
31470
- btnLabel.textContent = getSelectedPeriodsLabel(state5.selectedPeriods);
31487
+ btnLabel.textContent = getSelectedPeriodsLabel(state6.selectedPeriods);
31471
31488
  }
31472
- if (state5.data.length > 0) drawChart(modalId, state5);
31489
+ if (state6.data.length > 0) drawChart(modalId, state6);
31473
31490
  });
31474
31491
  });
31475
31492
  document.getElementById(`${modalId}-period-select-all`)?.addEventListener("click", () => {
31476
31493
  periodCheckboxes.forEach((cb) => {
31477
31494
  cb.checked = true;
31478
31495
  });
31479
- state5.selectedPeriods = ["madrugada", "manha", "tarde", "noite"];
31496
+ state6.selectedPeriods = ["madrugada", "manha", "tarde", "noite"];
31480
31497
  const btnLabel = periodBtn?.querySelector("span:first-child");
31481
31498
  if (btnLabel) {
31482
- btnLabel.textContent = getSelectedPeriodsLabel(state5.selectedPeriods);
31499
+ btnLabel.textContent = getSelectedPeriodsLabel(state6.selectedPeriods);
31483
31500
  }
31484
- if (state5.data.length > 0) drawChart(modalId, state5);
31501
+ if (state6.data.length > 0) drawChart(modalId, state6);
31485
31502
  });
31486
31503
  document.getElementById(`${modalId}-period-clear`)?.addEventListener("click", () => {
31487
31504
  periodCheckboxes.forEach((cb) => {
31488
31505
  cb.checked = false;
31489
31506
  });
31490
- state5.selectedPeriods = [];
31507
+ state6.selectedPeriods = [];
31491
31508
  const btnLabel = periodBtn?.querySelector("span:first-child");
31492
31509
  if (btnLabel) {
31493
- btnLabel.textContent = getSelectedPeriodsLabel(state5.selectedPeriods);
31510
+ btnLabel.textContent = getSelectedPeriodsLabel(state6.selectedPeriods);
31494
31511
  }
31495
- if (state5.data.length > 0) drawChart(modalId, state5);
31512
+ if (state6.data.length > 0) drawChart(modalId, state6);
31496
31513
  });
31497
31514
  document.getElementById(`${modalId}-granularity`)?.addEventListener("change", (e) => {
31498
- state5.granularity = e.target.value;
31499
- localStorage.setItem("myio-temp-modal-granularity", state5.granularity);
31500
- if (state5.data.length > 0) drawChart(modalId, state5);
31515
+ state6.granularity = e.target.value;
31516
+ localStorage.setItem("myio-temp-modal-granularity", state6.granularity);
31517
+ if (state6.data.length > 0) drawChart(modalId, state6);
31501
31518
  });
31502
31519
  document.getElementById(`${modalId}-query`)?.addEventListener("click", async () => {
31503
- if (state5.startTs >= state5.endTs) {
31520
+ if (state6.startTs >= state6.endTs) {
31504
31521
  alert("Por favor, selecione um per\xEDodo v\xE1lido");
31505
31522
  return;
31506
31523
  }
31507
- state5.isLoading = true;
31508
- state5.dateRangePicker = null;
31509
- renderModal(container, state5, modalId);
31524
+ state6.isLoading = true;
31525
+ state6.dateRangePicker = null;
31526
+ renderModal(container, state6, modalId);
31510
31527
  try {
31511
- state5.data = await fetchTemperatureData(state5.token, state5.deviceId, state5.startTs, state5.endTs);
31512
- state5.stats = calculateStats(state5.data, state5.clampRange);
31513
- state5.isLoading = false;
31514
- renderModal(container, state5, modalId);
31515
- drawChart(modalId, state5);
31516
- await setupEventListeners(container, state5, modalId, onClose);
31528
+ state6.data = await fetchTemperatureData(state6.token, state6.deviceId, state6.startTs, state6.endTs);
31529
+ state6.stats = calculateStats(state6.data, state6.clampRange);
31530
+ state6.isLoading = false;
31531
+ renderModal(container, state6, modalId);
31532
+ drawChart(modalId, state6);
31533
+ await setupEventListeners(container, state6, modalId, onClose);
31517
31534
  } catch (error) {
31518
31535
  console.error("[TemperatureModal] Error fetching data:", error);
31519
- state5.isLoading = false;
31520
- renderModal(container, state5, modalId, error);
31521
- await setupEventListeners(container, state5, modalId, onClose);
31536
+ state6.isLoading = false;
31537
+ renderModal(container, state6, modalId, error);
31538
+ await setupEventListeners(container, state6, modalId, onClose);
31522
31539
  }
31523
31540
  });
31524
31541
  document.getElementById(`${modalId}-export`)?.addEventListener("click", () => {
31525
- if (state5.data.length === 0) return;
31526
- const startDateStr = new Date(state5.startTs).toLocaleDateString(state5.locale).replace(/\//g, "-");
31527
- const endDateStr = new Date(state5.endTs).toLocaleDateString(state5.locale).replace(/\//g, "-");
31542
+ if (state6.data.length === 0) return;
31543
+ const startDateStr = new Date(state6.startTs).toLocaleDateString(state6.locale).replace(/\//g, "-");
31544
+ const endDateStr = new Date(state6.endTs).toLocaleDateString(state6.locale).replace(/\//g, "-");
31528
31545
  exportTemperatureCSV(
31529
- state5.data,
31530
- state5.label,
31531
- state5.stats,
31546
+ state6.data,
31547
+ state6.label,
31548
+ state6.stats,
31532
31549
  startDateStr,
31533
31550
  endDateStr
31534
31551
  );
@@ -31541,7 +31558,7 @@ async function openTemperatureComparisonModal(params) {
31541
31558
  const defaultDateRange = getTodaySoFar();
31542
31559
  const startTs = params.startDate ? new Date(params.startDate).getTime() : defaultDateRange.startTs;
31543
31560
  const endTs = params.endDate ? new Date(params.endDate).getTime() : defaultDateRange.endTs;
31544
- const state5 = {
31561
+ const state6 = {
31545
31562
  token: params.token,
31546
31563
  devices: params.devices,
31547
31564
  startTs,
@@ -31560,44 +31577,44 @@ async function openTemperatureComparisonModal(params) {
31560
31577
  };
31561
31578
  const savedGranularity = localStorage.getItem("myio-temp-comparison-granularity");
31562
31579
  const savedTheme = localStorage.getItem("myio-temp-comparison-theme");
31563
- if (savedGranularity) state5.granularity = savedGranularity;
31564
- if (savedTheme) state5.theme = savedTheme;
31580
+ if (savedGranularity) state6.granularity = savedGranularity;
31581
+ if (savedTheme) state6.theme = savedTheme;
31565
31582
  const modalContainer = document.createElement("div");
31566
31583
  modalContainer.id = modalId;
31567
31584
  document.body.appendChild(modalContainer);
31568
- renderModal2(modalContainer, state5, modalId);
31569
- await fetchAllDevicesData(state5);
31570
- renderModal2(modalContainer, state5, modalId);
31571
- drawComparisonChart(modalId, state5);
31572
- await setupEventListeners2(modalContainer, state5, modalId, params.onClose);
31585
+ renderModal2(modalContainer, state6, modalId);
31586
+ await fetchAllDevicesData(state6);
31587
+ renderModal2(modalContainer, state6, modalId);
31588
+ drawComparisonChart(modalId, state6);
31589
+ await setupEventListeners2(modalContainer, state6, modalId, params.onClose);
31573
31590
  return {
31574
31591
  destroy: () => {
31575
31592
  modalContainer.remove();
31576
31593
  params.onClose?.();
31577
31594
  },
31578
31595
  updateData: async (startDate, endDate, granularity) => {
31579
- state5.startTs = new Date(startDate).getTime();
31580
- state5.endTs = new Date(endDate).getTime();
31581
- if (granularity) state5.granularity = granularity;
31582
- state5.isLoading = true;
31583
- renderModal2(modalContainer, state5, modalId);
31584
- await fetchAllDevicesData(state5);
31585
- renderModal2(modalContainer, state5, modalId);
31586
- drawComparisonChart(modalId, state5);
31587
- setupEventListeners2(modalContainer, state5, modalId, params.onClose);
31596
+ state6.startTs = new Date(startDate).getTime();
31597
+ state6.endTs = new Date(endDate).getTime();
31598
+ if (granularity) state6.granularity = granularity;
31599
+ state6.isLoading = true;
31600
+ renderModal2(modalContainer, state6, modalId);
31601
+ await fetchAllDevicesData(state6);
31602
+ renderModal2(modalContainer, state6, modalId);
31603
+ drawComparisonChart(modalId, state6);
31604
+ setupEventListeners2(modalContainer, state6, modalId, params.onClose);
31588
31605
  }
31589
31606
  };
31590
31607
  }
31591
- async function fetchAllDevicesData(state5) {
31592
- state5.isLoading = true;
31593
- state5.deviceData = [];
31608
+ async function fetchAllDevicesData(state6) {
31609
+ state6.isLoading = true;
31610
+ state6.deviceData = [];
31594
31611
  try {
31595
31612
  const results = await Promise.all(
31596
- state5.devices.map(async (device, index) => {
31613
+ state6.devices.map(async (device, index) => {
31597
31614
  const deviceId = device.tbId || device.id;
31598
31615
  try {
31599
- const data = await fetchTemperatureData(state5.token, deviceId, state5.startTs, state5.endTs);
31600
- const stats = calculateStats(data, state5.clampRange);
31616
+ const data = await fetchTemperatureData(state6.token, deviceId, state6.startTs, state6.endTs);
31617
+ const stats = calculateStats(data, state6.clampRange);
31601
31618
  return {
31602
31619
  device,
31603
31620
  data,
@@ -31615,21 +31632,21 @@ async function fetchAllDevicesData(state5) {
31615
31632
  }
31616
31633
  })
31617
31634
  );
31618
- state5.deviceData = results;
31635
+ state6.deviceData = results;
31619
31636
  } catch (error) {
31620
31637
  console.error("[TemperatureComparisonModal] Error fetching data:", error);
31621
31638
  }
31622
- state5.isLoading = false;
31639
+ state6.isLoading = false;
31623
31640
  }
31624
- function renderModal2(container, state5, modalId) {
31625
- const colors = getThemeColors(state5.theme);
31626
- const startDateStr = new Date(state5.startTs).toLocaleDateString(state5.locale);
31627
- const endDateStr = new Date(state5.endTs).toLocaleDateString(state5.locale);
31628
- const startDateInput = new Date(state5.startTs).toISOString().slice(0, 16);
31629
- const endDateInput = new Date(state5.endTs).toISOString().slice(0, 16);
31630
- const legendHTML = state5.deviceData.map((dd) => `
31641
+ function renderModal2(container, state6, modalId) {
31642
+ const colors = getThemeColors(state6.theme);
31643
+ const startDateStr = new Date(state6.startTs).toLocaleDateString(state6.locale);
31644
+ const endDateStr = new Date(state6.endTs).toLocaleDateString(state6.locale);
31645
+ const startDateInput = new Date(state6.startTs).toISOString().slice(0, 16);
31646
+ const endDateInput = new Date(state6.endTs).toISOString().slice(0, 16);
31647
+ const legendHTML = state6.deviceData.map((dd) => `
31631
31648
  <div style="display: flex; align-items: center; gap: 8px; padding: 8px 12px;
31632
- background: ${state5.theme === "dark" ? "rgba(255,255,255,0.05)" : "rgba(0,0,0,0.03)"};
31649
+ background: ${state6.theme === "dark" ? "rgba(255,255,255,0.05)" : "rgba(0,0,0,0.03)"};
31633
31650
  border-radius: 8px;">
31634
31651
  <span style="width: 12px; height: 12px; border-radius: 50%; background: ${dd.color};"></span>
31635
31652
  <span style="color: ${colors.text}; font-size: 13px;">${dd.device.label}</span>
@@ -31638,9 +31655,9 @@ function renderModal2(container, state5, modalId) {
31638
31655
  </span>
31639
31656
  </div>
31640
31657
  `).join("");
31641
- const statsHTML = state5.deviceData.map((dd) => `
31658
+ const statsHTML = state6.deviceData.map((dd) => `
31642
31659
  <div style="
31643
- padding: 12px; background: ${state5.theme === "dark" ? "rgba(255,255,255,0.05)" : "#fafafa"};
31660
+ padding: 12px; background: ${state6.theme === "dark" ? "rgba(255,255,255,0.05)" : "#fafafa"};
31644
31661
  border-radius: 10px; border-left: 4px solid ${dd.color};
31645
31662
  min-width: 150px;
31646
31663
  ">
@@ -31691,7 +31708,7 @@ function renderModal2(container, state5, modalId) {
31691
31708
  min-height: 20px;
31692
31709
  ">
31693
31710
  <h2 style="margin: 6px; font-size: 18px; font-weight: 600; color: white; line-height: 2;">
31694
- \u{1F321}\uFE0F Compara\xE7\xE3o de Temperatura - ${state5.devices.length} sensores
31711
+ \u{1F321}\uFE0F Compara\xE7\xE3o de Temperatura - ${state6.devices.length} sensores
31695
31712
  </h2>
31696
31713
  <div style="display: flex; gap: 4px; align-items: center;">
31697
31714
  <!-- Theme Toggle -->
@@ -31699,7 +31716,7 @@ function renderModal2(container, state5, modalId) {
31699
31716
  background: none; border: none; font-size: 16px; cursor: pointer;
31700
31717
  padding: 4px 8px; border-radius: 6px; color: rgba(255,255,255,0.8);
31701
31718
  transition: background-color 0.2s;
31702
- ">${state5.theme === "dark" ? "\u2600\uFE0F" : "\u{1F319}"}</button>
31719
+ ">${state6.theme === "dark" ? "\u2600\uFE0F" : "\u{1F319}"}</button>
31703
31720
  <!-- Maximize Button -->
31704
31721
  <button id="${modalId}-maximize" title="${isMaximized ? "Restaurar" : "Maximizar"}" style="
31705
31722
  background: none; border: none; font-size: 16px; cursor: pointer;
@@ -31722,7 +31739,7 @@ function renderModal2(container, state5, modalId) {
31722
31739
  <div style="
31723
31740
  display: flex; gap: 16px; flex-wrap: wrap; align-items: flex-end;
31724
31741
  margin-bottom: 16px; padding: 16px;
31725
- background: ${state5.theme === "dark" ? "rgba(255,255,255,0.05)" : "#f7f7f7"};
31742
+ background: ${state6.theme === "dark" ? "rgba(255,255,255,0.05)" : "#f7f7f7"};
31726
31743
  border-radius: 6px; border: 1px solid ${colors.border};
31727
31744
  ">
31728
31745
  <!-- Granularity Select -->
@@ -31735,8 +31752,8 @@ function renderModal2(container, state5, modalId) {
31735
31752
  font-size: 14px; color: ${colors.text}; background: ${colors.surface};
31736
31753
  cursor: pointer; min-width: 130px;
31737
31754
  ">
31738
- <option value="hour" ${state5.granularity === "hour" ? "selected" : ""}>Hora (30 min)</option>
31739
- <option value="day" ${state5.granularity === "day" ? "selected" : ""}>Dia (m\xE9dia)</option>
31755
+ <option value="hour" ${state6.granularity === "hour" ? "selected" : ""}>Hora (30 min)</option>
31756
+ <option value="day" ${state6.granularity === "day" ? "selected" : ""}>Dia (m\xE9dia)</option>
31740
31757
  </select>
31741
31758
  </div>
31742
31759
  <!-- Day Period Filter (Multiselect) -->
@@ -31750,7 +31767,7 @@ function renderModal2(container, state5, modalId) {
31750
31767
  cursor: pointer; min-width: 180px; text-align: left;
31751
31768
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
31752
31769
  ">
31753
- <span>${getSelectedPeriodsLabel(state5.selectedPeriods)}</span>
31770
+ <span>${getSelectedPeriodsLabel(state6.selectedPeriods)}</span>
31754
31771
  <span style="font-size: 10px;">\u25BC</span>
31755
31772
  </button>
31756
31773
  <div id="${modalId}-period-dropdown" style="
@@ -31763,12 +31780,12 @@ function renderModal2(container, state5, modalId) {
31763
31780
  <label style="
31764
31781
  display: flex; align-items: center; gap: 8px; padding: 8px 12px;
31765
31782
  cursor: pointer; font-size: 13px; color: ${colors.text};
31766
- " onmouseover="this.style.background='${state5.theme === "dark" ? "rgba(255,255,255,0.1)" : "#f0f0f0"}'"
31783
+ " onmouseover="this.style.background='${state6.theme === "dark" ? "rgba(255,255,255,0.1)" : "#f0f0f0"}'"
31767
31784
  onmouseout="this.style.background='transparent'">
31768
31785
  <input type="checkbox"
31769
31786
  name="${modalId}-period"
31770
31787
  value="${period.id}"
31771
- ${state5.selectedPeriods.includes(period.id) ? "checked" : ""}
31788
+ ${state6.selectedPeriods.includes(period.id) ? "checked" : ""}
31772
31789
  style="width: 16px; height: 16px; cursor: pointer; accent-color: #3e1a7d;">
31773
31790
  ${period.label}
31774
31791
  </label>
@@ -31776,13 +31793,13 @@ function renderModal2(container, state5, modalId) {
31776
31793
  <div style="border-top: 1px solid ${colors.border}; margin-top: 8px; padding-top: 8px;">
31777
31794
  <button id="${modalId}-period-select-all" type="button" style="
31778
31795
  width: calc(100% - 16px); margin: 0 8px 4px; padding: 6px;
31779
- background: ${state5.theme === "dark" ? "rgba(255,255,255,0.1)" : "#f0f0f0"};
31796
+ background: ${state6.theme === "dark" ? "rgba(255,255,255,0.1)" : "#f0f0f0"};
31780
31797
  border: none; border-radius: 4px; cursor: pointer;
31781
31798
  font-size: 12px; color: ${colors.text};
31782
31799
  ">Selecionar Todos</button>
31783
31800
  <button id="${modalId}-period-clear" type="button" style="
31784
31801
  width: calc(100% - 16px); margin: 0 8px; padding: 6px;
31785
- background: ${state5.theme === "dark" ? "rgba(255,255,255,0.1)" : "#f0f0f0"};
31802
+ background: ${state6.theme === "dark" ? "rgba(255,255,255,0.1)" : "#f0f0f0"};
31786
31803
  border: none; border-radius: 4px; cursor: pointer;
31787
31804
  font-size: 12px; color: ${colors.text};
31788
31805
  ">Limpar Sele\xE7\xE3o</button>
@@ -31807,8 +31824,8 @@ function renderModal2(container, state5, modalId) {
31807
31824
  font-size: 14px; font-weight: 500; height: 38px;
31808
31825
  display: flex; align-items: center; gap: 8px;
31809
31826
  font-family: 'Roboto', Arial, sans-serif;
31810
- " ${state5.isLoading ? "disabled" : ""}>
31811
- ${state5.isLoading ? '<span style="animation: spin 1s linear infinite; display: inline-block;">\u21BB</span> Carregando...' : "Carregar"}
31827
+ " ${state6.isLoading ? "disabled" : ""}>
31828
+ ${state6.isLoading ? '<span style="animation: spin 1s linear infinite; display: inline-block;">\u21BB</span> Carregando...' : "Carregar"}
31812
31829
  </button>
31813
31830
  </div>
31814
31831
 
@@ -31824,14 +31841,14 @@ function renderModal2(container, state5, modalId) {
31824
31841
  <div style="margin-bottom: 24px;">
31825
31842
  <div id="${modalId}-chart" style="
31826
31843
  height: 380px;
31827
- background: ${state5.theme === "dark" ? "rgba(255,255,255,0.03)" : "#fafafa"};
31844
+ background: ${state6.theme === "dark" ? "rgba(255,255,255,0.03)" : "#fafafa"};
31828
31845
  border-radius: 14px; display: flex; justify-content: center; align-items: center;
31829
31846
  border: 1px solid ${colors.border}; position: relative;
31830
31847
  ">
31831
- ${state5.isLoading ? `<div style="text-align: center; color: ${colors.textMuted};">
31848
+ ${state6.isLoading ? `<div style="text-align: center; color: ${colors.textMuted};">
31832
31849
  <div style="animation: spin 1s linear infinite; font-size: 36px; margin-bottom: 12px;">\u21BB</div>
31833
- <div style="font-size: 15px;">Carregando dados de ${state5.devices.length} sensores...</div>
31834
- </div>` : state5.deviceData.every((dd) => dd.data.length === 0) ? `<div style="text-align: center; color: ${colors.textMuted};">
31850
+ <div style="font-size: 15px;">Carregando dados de ${state6.devices.length} sensores...</div>
31851
+ </div>` : state6.deviceData.every((dd) => dd.data.length === 0) ? `<div style="text-align: center; color: ${colors.textMuted};">
31835
31852
  <div style="font-size: 48px; margin-bottom: 12px;">\u{1F4ED}</div>
31836
31853
  <div style="font-size: 16px;">Sem dados para o per\xEDodo selecionado</div>
31837
31854
  </div>` : `<canvas id="${modalId}-canvas" style="width: 100%; height: 100%;"></canvas>`}
@@ -31849,12 +31866,12 @@ function renderModal2(container, state5, modalId) {
31849
31866
  <!-- Actions -->
31850
31867
  <div style="display: flex; justify-content: flex-end; gap: 12px;">
31851
31868
  <button id="${modalId}-export" style="
31852
- background: ${state5.theme === "dark" ? "rgba(255,255,255,0.1)" : "#f7f7f7"};
31869
+ background: ${state6.theme === "dark" ? "rgba(255,255,255,0.1)" : "#f7f7f7"};
31853
31870
  color: ${colors.text}; border: 1px solid ${colors.border};
31854
31871
  padding: 8px 16px; border-radius: 6px; cursor: pointer;
31855
31872
  font-size: 14px; display: flex; align-items: center; gap: 8px;
31856
31873
  font-family: 'Roboto', Arial, sans-serif;
31857
- " ${state5.deviceData.every((dd) => dd.data.length === 0) ? "disabled" : ""}>
31874
+ " ${state6.deviceData.every((dd) => dd.data.length === 0) ? "disabled" : ""}>
31858
31875
  \u{1F4E5} Exportar CSV
31859
31876
  </button>
31860
31877
  <button id="${modalId}-close-btn" style="
@@ -31889,15 +31906,15 @@ function renderModal2(container, state5, modalId) {
31889
31906
  </style>
31890
31907
  `;
31891
31908
  }
31892
- function drawComparisonChart(modalId, state5) {
31909
+ function drawComparisonChart(modalId, state6) {
31893
31910
  const chartContainer = document.getElementById(`${modalId}-chart`);
31894
31911
  const canvas = document.getElementById(`${modalId}-canvas`);
31895
31912
  if (!chartContainer || !canvas) return;
31896
- const hasData = state5.deviceData.some((dd) => dd.data.length > 0);
31913
+ const hasData = state6.deviceData.some((dd) => dd.data.length > 0);
31897
31914
  if (!hasData) return;
31898
31915
  const ctx = canvas.getContext("2d");
31899
31916
  if (!ctx) return;
31900
- const colors = getThemeColors(state5.theme);
31917
+ const colors = getThemeColors(state6.theme);
31901
31918
  const width = chartContainer.clientWidth - 2;
31902
31919
  const height = 380;
31903
31920
  canvas.width = width;
@@ -31908,19 +31925,19 @@ function drawComparisonChart(modalId, state5) {
31908
31925
  const paddingBottom = 55;
31909
31926
  ctx.clearRect(0, 0, width, height);
31910
31927
  const processedData = [];
31911
- state5.deviceData.forEach((dd) => {
31928
+ state6.deviceData.forEach((dd) => {
31912
31929
  if (dd.data.length === 0) return;
31913
- const filteredData = filterByDayPeriods(dd.data, state5.selectedPeriods);
31930
+ const filteredData = filterByDayPeriods(dd.data, state6.selectedPeriods);
31914
31931
  if (filteredData.length === 0) return;
31915
31932
  let points;
31916
- if (state5.granularity === "hour") {
31933
+ if (state6.granularity === "hour") {
31917
31934
  const interpolated = interpolateTemperature(filteredData, {
31918
31935
  intervalMinutes: 30,
31919
- startTs: state5.startTs,
31920
- endTs: state5.endTs,
31921
- clampRange: state5.clampRange
31936
+ startTs: state6.startTs,
31937
+ endTs: state6.endTs,
31938
+ clampRange: state6.clampRange
31922
31939
  });
31923
- const filteredInterpolated = filterByDayPeriods(interpolated, state5.selectedPeriods);
31940
+ const filteredInterpolated = filterByDayPeriods(interpolated, state6.selectedPeriods);
31924
31941
  points = filteredInterpolated.map((item) => ({
31925
31942
  x: item.ts,
31926
31943
  y: Number(item.value),
@@ -31930,7 +31947,7 @@ function drawComparisonChart(modalId, state5) {
31930
31947
  deviceColor: dd.color
31931
31948
  }));
31932
31949
  } else {
31933
- const daily = aggregateByDay(filteredData, state5.clampRange);
31950
+ const daily = aggregateByDay(filteredData, state6.clampRange);
31934
31951
  points = daily.map((item) => ({
31935
31952
  x: item.dateTs,
31936
31953
  y: item.avg,
@@ -31951,7 +31968,7 @@ function drawComparisonChart(modalId, state5) {
31951
31968
  ctx.fillText("Nenhum dado para os per\xEDodos selecionados", width / 2, height / 2);
31952
31969
  return;
31953
31970
  }
31954
- const isPeriodsFiltered = state5.selectedPeriods.length < 4 && state5.selectedPeriods.length > 0;
31971
+ const isPeriodsFiltered = state6.selectedPeriods.length < 4 && state6.selectedPeriods.length > 0;
31955
31972
  let dataMinY = Infinity;
31956
31973
  let dataMaxY = -Infinity;
31957
31974
  processedData.forEach(({ points }) => {
@@ -31961,7 +31978,7 @@ function drawComparisonChart(modalId, state5) {
31961
31978
  });
31962
31979
  });
31963
31980
  const rangeMap = /* @__PURE__ */ new Map();
31964
- state5.deviceData.forEach((dd, index) => {
31981
+ state6.deviceData.forEach((dd, index) => {
31965
31982
  const device = dd.device;
31966
31983
  const min = device.temperatureMin;
31967
31984
  const max = device.temperatureMax;
@@ -31980,10 +31997,10 @@ function drawComparisonChart(modalId, state5) {
31980
31997
  }
31981
31998
  }
31982
31999
  });
31983
- if (rangeMap.size === 0 && state5.temperatureMin !== null && state5.temperatureMax !== null) {
32000
+ if (rangeMap.size === 0 && state6.temperatureMin !== null && state6.temperatureMax !== null) {
31984
32001
  rangeMap.set("global", {
31985
- min: state5.temperatureMin,
31986
- max: state5.temperatureMax,
32002
+ min: state6.temperatureMin,
32003
+ max: state6.temperatureMax,
31987
32004
  customerName: "Global",
31988
32005
  color: colors.success,
31989
32006
  deviceLabels: []
@@ -32104,10 +32121,10 @@ function drawComparisonChart(modalId, state5) {
32104
32121
  const point = xAxisPoints[i];
32105
32122
  const date = new Date(point.x);
32106
32123
  let label;
32107
- if (state5.granularity === "hour") {
32108
- label = date.toLocaleTimeString(state5.locale, { hour: "2-digit", minute: "2-digit" });
32124
+ if (state6.granularity === "hour") {
32125
+ label = date.toLocaleTimeString(state6.locale, { hour: "2-digit", minute: "2-digit" });
32109
32126
  } else {
32110
- label = date.toLocaleDateString(state5.locale, { day: "2-digit", month: "2-digit" });
32127
+ label = date.toLocaleDateString(state6.locale, { day: "2-digit", month: "2-digit" });
32111
32128
  }
32112
32129
  ctx.strokeStyle = colors.chartGrid;
32113
32130
  ctx.lineWidth = 1;
@@ -32126,16 +32143,16 @@ function drawComparisonChart(modalId, state5) {
32126
32143
  ctx.lineTo(width - paddingRight, height - paddingBottom);
32127
32144
  ctx.stroke();
32128
32145
  const allChartPoints = processedData.flatMap((pd) => pd.points);
32129
- setupComparisonChartTooltip(canvas, chartContainer, allChartPoints, state5, colors);
32146
+ setupComparisonChartTooltip(canvas, chartContainer, allChartPoints, state6, colors);
32130
32147
  }
32131
- function setupComparisonChartTooltip(canvas, container, chartData, state5, colors) {
32148
+ function setupComparisonChartTooltip(canvas, container, chartData, state6, colors) {
32132
32149
  const existingTooltip = container.querySelector(".myio-chart-tooltip");
32133
32150
  if (existingTooltip) existingTooltip.remove();
32134
32151
  const tooltip = document.createElement("div");
32135
32152
  tooltip.className = "myio-chart-tooltip";
32136
32153
  tooltip.style.cssText = `
32137
32154
  position: absolute;
32138
- background: ${state5.theme === "dark" ? "rgba(30, 30, 40, 0.95)" : "rgba(255, 255, 255, 0.98)"};
32155
+ background: ${state6.theme === "dark" ? "rgba(30, 30, 40, 0.95)" : "rgba(255, 255, 255, 0.98)"};
32139
32156
  border: 1px solid ${colors.border};
32140
32157
  border-radius: 8px;
32141
32158
  padding: 10px 14px;
@@ -32172,17 +32189,17 @@ function setupComparisonChartTooltip(canvas, container, chartData, state5, color
32172
32189
  if (point) {
32173
32190
  const date = new Date(point.x);
32174
32191
  let dateStr;
32175
- if (state5.granularity === "hour") {
32176
- dateStr = date.toLocaleDateString(state5.locale, {
32192
+ if (state6.granularity === "hour") {
32193
+ dateStr = date.toLocaleDateString(state6.locale, {
32177
32194
  day: "2-digit",
32178
32195
  month: "2-digit",
32179
32196
  year: "numeric"
32180
- }) + " " + date.toLocaleTimeString(state5.locale, {
32197
+ }) + " " + date.toLocaleTimeString(state6.locale, {
32181
32198
  hour: "2-digit",
32182
32199
  minute: "2-digit"
32183
32200
  });
32184
32201
  } else {
32185
- dateStr = date.toLocaleDateString(state5.locale, {
32202
+ dateStr = date.toLocaleDateString(state6.locale, {
32186
32203
  day: "2-digit",
32187
32204
  month: "2-digit",
32188
32205
  year: "numeric"
@@ -32224,7 +32241,7 @@ function setupComparisonChartTooltip(canvas, container, chartData, state5, color
32224
32241
  canvas.style.cursor = "default";
32225
32242
  });
32226
32243
  }
32227
- async function setupEventListeners2(container, state5, modalId, onClose) {
32244
+ async function setupEventListeners2(container, state6, modalId, onClose) {
32228
32245
  const closeModal = () => {
32229
32246
  container.remove();
32230
32247
  onClose?.();
@@ -32235,19 +32252,19 @@ async function setupEventListeners2(container, state5, modalId, onClose) {
32235
32252
  document.getElementById(`${modalId}-close`)?.addEventListener("click", closeModal);
32236
32253
  document.getElementById(`${modalId}-close-btn`)?.addEventListener("click", closeModal);
32237
32254
  const dateRangeInput = document.getElementById(`${modalId}-date-range`);
32238
- if (dateRangeInput && !state5.dateRangePicker) {
32255
+ if (dateRangeInput && !state6.dateRangePicker) {
32239
32256
  try {
32240
- state5.dateRangePicker = await createDateRangePicker2(dateRangeInput, {
32241
- presetStart: new Date(state5.startTs).toISOString(),
32242
- presetEnd: new Date(state5.endTs).toISOString(),
32257
+ state6.dateRangePicker = await createDateRangePicker2(dateRangeInput, {
32258
+ presetStart: new Date(state6.startTs).toISOString(),
32259
+ presetEnd: new Date(state6.endTs).toISOString(),
32243
32260
  includeTime: true,
32244
32261
  timePrecision: "minute",
32245
32262
  maxRangeDays: 90,
32246
- locale: state5.locale,
32263
+ locale: state6.locale,
32247
32264
  parentEl: container.querySelector(".myio-temp-comparison-content"),
32248
32265
  onApply: (result) => {
32249
- state5.startTs = new Date(result.startISO).getTime();
32250
- state5.endTs = new Date(result.endISO).getTime();
32266
+ state6.startTs = new Date(result.startISO).getTime();
32267
+ state6.endTs = new Date(result.endISO).getTime();
32251
32268
  console.log("[TemperatureComparisonModal] Date range applied:", result);
32252
32269
  }
32253
32270
  });
@@ -32256,23 +32273,23 @@ async function setupEventListeners2(container, state5, modalId, onClose) {
32256
32273
  }
32257
32274
  }
32258
32275
  document.getElementById(`${modalId}-theme-toggle`)?.addEventListener("click", async () => {
32259
- state5.theme = state5.theme === "dark" ? "light" : "dark";
32260
- localStorage.setItem("myio-temp-comparison-theme", state5.theme);
32261
- state5.dateRangePicker = null;
32262
- renderModal2(container, state5, modalId);
32263
- if (state5.deviceData.some((dd) => dd.data.length > 0)) {
32264
- drawComparisonChart(modalId, state5);
32265
- }
32266
- await setupEventListeners2(container, state5, modalId, onClose);
32276
+ state6.theme = state6.theme === "dark" ? "light" : "dark";
32277
+ localStorage.setItem("myio-temp-comparison-theme", state6.theme);
32278
+ state6.dateRangePicker = null;
32279
+ renderModal2(container, state6, modalId);
32280
+ if (state6.deviceData.some((dd) => dd.data.length > 0)) {
32281
+ drawComparisonChart(modalId, state6);
32282
+ }
32283
+ await setupEventListeners2(container, state6, modalId, onClose);
32267
32284
  });
32268
32285
  document.getElementById(`${modalId}-maximize`)?.addEventListener("click", async () => {
32269
32286
  container.__isMaximized = !container.__isMaximized;
32270
- state5.dateRangePicker = null;
32271
- renderModal2(container, state5, modalId);
32272
- if (state5.deviceData.some((dd) => dd.data.length > 0)) {
32273
- drawComparisonChart(modalId, state5);
32287
+ state6.dateRangePicker = null;
32288
+ renderModal2(container, state6, modalId);
32289
+ if (state6.deviceData.some((dd) => dd.data.length > 0)) {
32290
+ drawComparisonChart(modalId, state6);
32274
32291
  }
32275
- await setupEventListeners2(container, state5, modalId, onClose);
32292
+ await setupEventListeners2(container, state6, modalId, onClose);
32276
32293
  });
32277
32294
  const periodBtn = document.getElementById(`${modalId}-period-btn`);
32278
32295
  const periodDropdown = document.getElementById(`${modalId}-period-dropdown`);
@@ -32291,13 +32308,13 @@ async function setupEventListeners2(container, state5, modalId, onClose) {
32291
32308
  periodCheckboxes.forEach((checkbox) => {
32292
32309
  checkbox.addEventListener("change", () => {
32293
32310
  const checked = Array.from(periodCheckboxes).filter((cb) => cb.checked).map((cb) => cb.value);
32294
- state5.selectedPeriods = checked;
32311
+ state6.selectedPeriods = checked;
32295
32312
  const btnLabel = periodBtn?.querySelector("span:first-child");
32296
32313
  if (btnLabel) {
32297
- btnLabel.textContent = getSelectedPeriodsLabel(state5.selectedPeriods);
32314
+ btnLabel.textContent = getSelectedPeriodsLabel(state6.selectedPeriods);
32298
32315
  }
32299
- if (state5.deviceData.some((dd) => dd.data.length > 0)) {
32300
- drawComparisonChart(modalId, state5);
32316
+ if (state6.deviceData.some((dd) => dd.data.length > 0)) {
32317
+ drawComparisonChart(modalId, state6);
32301
32318
  }
32302
32319
  });
32303
32320
  });
@@ -32305,77 +32322,77 @@ async function setupEventListeners2(container, state5, modalId, onClose) {
32305
32322
  periodCheckboxes.forEach((cb) => {
32306
32323
  cb.checked = true;
32307
32324
  });
32308
- state5.selectedPeriods = ["madrugada", "manha", "tarde", "noite"];
32325
+ state6.selectedPeriods = ["madrugada", "manha", "tarde", "noite"];
32309
32326
  const btnLabel = periodBtn?.querySelector("span:first-child");
32310
32327
  if (btnLabel) {
32311
- btnLabel.textContent = getSelectedPeriodsLabel(state5.selectedPeriods);
32328
+ btnLabel.textContent = getSelectedPeriodsLabel(state6.selectedPeriods);
32312
32329
  }
32313
- if (state5.deviceData.some((dd) => dd.data.length > 0)) {
32314
- drawComparisonChart(modalId, state5);
32330
+ if (state6.deviceData.some((dd) => dd.data.length > 0)) {
32331
+ drawComparisonChart(modalId, state6);
32315
32332
  }
32316
32333
  });
32317
32334
  document.getElementById(`${modalId}-period-clear`)?.addEventListener("click", () => {
32318
32335
  periodCheckboxes.forEach((cb) => {
32319
32336
  cb.checked = false;
32320
32337
  });
32321
- state5.selectedPeriods = [];
32338
+ state6.selectedPeriods = [];
32322
32339
  const btnLabel = periodBtn?.querySelector("span:first-child");
32323
32340
  if (btnLabel) {
32324
- btnLabel.textContent = getSelectedPeriodsLabel(state5.selectedPeriods);
32341
+ btnLabel.textContent = getSelectedPeriodsLabel(state6.selectedPeriods);
32325
32342
  }
32326
- if (state5.deviceData.some((dd) => dd.data.length > 0)) {
32327
- drawComparisonChart(modalId, state5);
32343
+ if (state6.deviceData.some((dd) => dd.data.length > 0)) {
32344
+ drawComparisonChart(modalId, state6);
32328
32345
  }
32329
32346
  });
32330
32347
  document.getElementById(`${modalId}-granularity`)?.addEventListener("change", (e) => {
32331
- state5.granularity = e.target.value;
32332
- localStorage.setItem("myio-temp-comparison-granularity", state5.granularity);
32333
- if (state5.deviceData.some((dd) => dd.data.length > 0)) {
32334
- drawComparisonChart(modalId, state5);
32348
+ state6.granularity = e.target.value;
32349
+ localStorage.setItem("myio-temp-comparison-granularity", state6.granularity);
32350
+ if (state6.deviceData.some((dd) => dd.data.length > 0)) {
32351
+ drawComparisonChart(modalId, state6);
32335
32352
  }
32336
32353
  });
32337
32354
  document.getElementById(`${modalId}-query`)?.addEventListener("click", async () => {
32338
- if (state5.startTs >= state5.endTs) {
32355
+ if (state6.startTs >= state6.endTs) {
32339
32356
  alert("Por favor, selecione um per\xEDodo v\xE1lido");
32340
32357
  return;
32341
32358
  }
32342
- state5.isLoading = true;
32343
- state5.dateRangePicker = null;
32344
- renderModal2(container, state5, modalId);
32345
- await fetchAllDevicesData(state5);
32346
- renderModal2(container, state5, modalId);
32347
- drawComparisonChart(modalId, state5);
32348
- await setupEventListeners2(container, state5, modalId, onClose);
32359
+ state6.isLoading = true;
32360
+ state6.dateRangePicker = null;
32361
+ renderModal2(container, state6, modalId);
32362
+ await fetchAllDevicesData(state6);
32363
+ renderModal2(container, state6, modalId);
32364
+ drawComparisonChart(modalId, state6);
32365
+ await setupEventListeners2(container, state6, modalId, onClose);
32349
32366
  });
32350
32367
  document.getElementById(`${modalId}-export`)?.addEventListener("click", () => {
32351
- if (state5.deviceData.every((dd) => dd.data.length === 0)) return;
32352
- exportComparisonCSV(state5);
32368
+ if (state6.deviceData.every((dd) => dd.data.length === 0)) return;
32369
+ exportComparisonCSV(state6);
32353
32370
  });
32354
32371
  }
32355
- function exportComparisonCSV(state5) {
32356
- const startDateStr = new Date(state5.startTs).toLocaleDateString(state5.locale).replace(/\//g, "-");
32357
- const endDateStr = new Date(state5.endTs).toLocaleDateString(state5.locale).replace(/\//g, "-");
32372
+ function exportComparisonCSV(state6) {
32373
+ const startDateStr = new Date(state6.startTs).toLocaleDateString(state6.locale).replace(/\//g, "-");
32374
+ const endDateStr = new Date(state6.endTs).toLocaleDateString(state6.locale).replace(/\//g, "-");
32358
32375
  const BOM = "\uFEFF";
32359
32376
  let csvContent = BOM;
32360
32377
  csvContent += `Compara\xE7\xE3o de Temperatura
32361
32378
  `;
32362
32379
  csvContent += `Per\xEDodo: ${startDateStr} at\xE9 ${endDateStr}
32363
32380
  `;
32364
- csvContent += `Sensores: ${state5.devices.map((d) => d.label).join(", ")}
32381
+ csvContent += `Sensores: ${state6.devices.map((d) => d.label).join(", ")}
32365
32382
  `;
32366
32383
  csvContent += "\n";
32367
32384
  csvContent += "Estat\xEDsticas por Sensor:\n";
32368
32385
  csvContent += "Sensor,M\xE9dia (\xB0C),Min (\xB0C),Max (\xB0C),Leituras\n";
32369
- state5.deviceData.forEach((dd) => {
32386
+ state6.deviceData.forEach((dd) => {
32370
32387
  csvContent += `"${dd.device.label}",${dd.stats.avg.toFixed(2)},${dd.stats.min.toFixed(2)},${dd.stats.max.toFixed(2)},${dd.stats.count}
32371
32388
  `;
32372
32389
  });
32373
32390
  csvContent += "\n";
32374
32391
  csvContent += "Dados Detalhados:\n";
32375
32392
  csvContent += "Data/Hora,Sensor,Temperatura (\xB0C)\n";
32376
- state5.deviceData.forEach((dd) => {
32393
+ state6.deviceData.forEach((dd) => {
32377
32394
  dd.data.forEach((item) => {
32378
- const date = new Date(item.ts).toLocaleString(state5.locale);
32395
+ const date = new Date(item.ts).toLocaleString(state6.locale);
32379
32396
  const temp = Number(item.value).toFixed(2);
32380
32397
  csvContent += `"${date}","${dd.device.label}",${temp}
32381
32398
  `;
@@ -32483,10 +32500,10 @@ async function saveCustomerAttributes(customerId, token, minTemperature, maxTemp
32483
32500
  throw new Error(`Failed to save attributes: ${response.status}`);
32484
32501
  }
32485
32502
  }
32486
- function renderModal3(container, state5, modalId, onClose, onSave) {
32487
- const colors = getColors(state5.theme);
32488
- const minValue = state5.minTemperature !== null ? state5.minTemperature : "";
32489
- const maxValue = state5.maxTemperature !== null ? state5.maxTemperature : "";
32503
+ function renderModal3(container, state6, modalId, onClose, onSave) {
32504
+ const colors = getColors(state6.theme);
32505
+ const minValue = state6.minTemperature !== null ? state6.minTemperature : "";
32506
+ const maxValue = state6.maxTemperature !== null ? state6.maxTemperature : "";
32490
32507
  container.innerHTML = `
32491
32508
  <style>
32492
32509
  @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@@ -32751,23 +32768,23 @@ function renderModal3(container, state5, modalId, onClose, onSave) {
32751
32768
  </div>
32752
32769
 
32753
32770
  <div class="modal-body">
32754
- ${state5.isLoading ? `
32771
+ ${state6.isLoading ? `
32755
32772
  <div class="loading-overlay">
32756
32773
  <div class="loading-spinner"></div>
32757
32774
  <div>Carregando configura\xE7\xF5es...</div>
32758
32775
  </div>
32759
32776
  ` : `
32760
- ${state5.error ? `
32761
- <div class="message message-error">${state5.error}</div>
32777
+ ${state6.error ? `
32778
+ <div class="message message-error">${state6.error}</div>
32762
32779
  ` : ""}
32763
32780
 
32764
- ${state5.successMessage ? `
32765
- <div class="message message-success">${state5.successMessage}</div>
32781
+ ${state6.successMessage ? `
32782
+ <div class="message message-success">${state6.successMessage}</div>
32766
32783
  ` : ""}
32767
32784
 
32768
32785
  <div class="customer-info">
32769
32786
  <div class="customer-label">Shopping / Cliente</div>
32770
- <div class="customer-name">${state5.customerName || "N\xE3o identificado"}</div>
32787
+ <div class="customer-name">${state6.customerName || "N\xE3o identificado"}</div>
32771
32788
  </div>
32772
32789
 
32773
32790
  <div class="form-group">
@@ -32811,11 +32828,11 @@ function renderModal3(container, state5, modalId, onClose, onSave) {
32811
32828
  `}
32812
32829
  </div>
32813
32830
 
32814
- ${!state5.isLoading ? `
32831
+ ${!state6.isLoading ? `
32815
32832
  <div class="modal-footer">
32816
32833
  <button class="btn btn-secondary" id="${modalId}-cancel">Cancelar</button>
32817
- <button class="btn btn-primary" id="${modalId}-save" ${state5.isSaving ? "disabled" : ""}>
32818
- ${state5.isSaving ? '<div class="spinner"></div> Salvando...' : "Salvar"}
32834
+ <button class="btn btn-primary" id="${modalId}-save" ${state6.isSaving ? "disabled" : ""}>
32835
+ ${state6.isSaving ? '<div class="spinner"></div> Salvando...' : "Salvar"}
32819
32836
  </button>
32820
32837
  </div>
32821
32838
  ` : ""}
@@ -32852,18 +32869,18 @@ function renderModal3(container, state5, modalId, onClose, onSave) {
32852
32869
  const min = parseFloat(minInput.value);
32853
32870
  const max = parseFloat(maxInput.value);
32854
32871
  if (isNaN(min) || isNaN(max)) {
32855
- state5.error = "Por favor, preencha ambos os valores.";
32856
- renderModal3(container, state5, modalId, onClose, onSave);
32872
+ state6.error = "Por favor, preencha ambos os valores.";
32873
+ renderModal3(container, state6, modalId, onClose, onSave);
32857
32874
  return;
32858
32875
  }
32859
32876
  if (min >= max) {
32860
- state5.error = "A temperatura m\xEDnima deve ser menor que a m\xE1xima.";
32861
- renderModal3(container, state5, modalId, onClose, onSave);
32877
+ state6.error = "A temperatura m\xEDnima deve ser menor que a m\xE1xima.";
32878
+ renderModal3(container, state6, modalId, onClose, onSave);
32862
32879
  return;
32863
32880
  }
32864
32881
  if (min < 0 || max > 50) {
32865
- state5.error = "Os valores devem estar entre 0\xB0C e 50\xB0C.";
32866
- renderModal3(container, state5, modalId, onClose, onSave);
32882
+ state6.error = "Os valores devem estar entre 0\xB0C e 50\xB0C.";
32883
+ renderModal3(container, state6, modalId, onClose, onSave);
32867
32884
  return;
32868
32885
  }
32869
32886
  await onSave(min, max);
@@ -32871,7 +32888,7 @@ function renderModal3(container, state5, modalId, onClose, onSave) {
32871
32888
  }
32872
32889
  function openTemperatureSettingsModal(params) {
32873
32890
  const modalId = `myio-temp-settings-${Date.now()}`;
32874
- const state5 = {
32891
+ const state6 = {
32875
32892
  customerId: params.customerId,
32876
32893
  customerName: params.customerName || "",
32877
32894
  token: params.token,
@@ -32891,37 +32908,37 @@ function openTemperatureSettingsModal(params) {
32891
32908
  params.onClose?.();
32892
32909
  };
32893
32910
  const handleSave = async (min, max) => {
32894
- state5.isSaving = true;
32895
- state5.error = null;
32896
- state5.successMessage = null;
32897
- renderModal3(container, state5, modalId, destroy, handleSave);
32911
+ state6.isSaving = true;
32912
+ state6.error = null;
32913
+ state6.successMessage = null;
32914
+ renderModal3(container, state6, modalId, destroy, handleSave);
32898
32915
  try {
32899
- await saveCustomerAttributes(state5.customerId, state5.token, min, max, params.onError);
32900
- state5.minTemperature = min;
32901
- state5.maxTemperature = max;
32902
- state5.isSaving = false;
32903
- state5.successMessage = "Configura\xE7\xF5es salvas com sucesso!";
32904
- renderModal3(container, state5, modalId, destroy, handleSave);
32916
+ await saveCustomerAttributes(state6.customerId, state6.token, min, max, params.onError);
32917
+ state6.minTemperature = min;
32918
+ state6.maxTemperature = max;
32919
+ state6.isSaving = false;
32920
+ state6.successMessage = "Configura\xE7\xF5es salvas com sucesso!";
32921
+ renderModal3(container, state6, modalId, destroy, handleSave);
32905
32922
  params.onSave?.({ minTemperature: min, maxTemperature: max });
32906
32923
  setTimeout(() => {
32907
32924
  destroy();
32908
32925
  }, 1500);
32909
32926
  } catch (error) {
32910
- state5.isSaving = false;
32911
- state5.error = `Erro ao salvar: ${error.message}`;
32912
- renderModal3(container, state5, modalId, destroy, handleSave);
32927
+ state6.isSaving = false;
32928
+ state6.error = `Erro ao salvar: ${error.message}`;
32929
+ renderModal3(container, state6, modalId, destroy, handleSave);
32913
32930
  }
32914
32931
  };
32915
- renderModal3(container, state5, modalId, destroy, handleSave);
32916
- fetchCustomerAttributes(state5.customerId, state5.token, params.onError).then(({ minTemperature, maxTemperature }) => {
32917
- state5.minTemperature = minTemperature;
32918
- state5.maxTemperature = maxTemperature;
32919
- state5.isLoading = false;
32920
- renderModal3(container, state5, modalId, destroy, handleSave);
32932
+ renderModal3(container, state6, modalId, destroy, handleSave);
32933
+ fetchCustomerAttributes(state6.customerId, state6.token, params.onError).then(({ minTemperature, maxTemperature }) => {
32934
+ state6.minTemperature = minTemperature;
32935
+ state6.maxTemperature = maxTemperature;
32936
+ state6.isLoading = false;
32937
+ renderModal3(container, state6, modalId, destroy, handleSave);
32921
32938
  }).catch((error) => {
32922
- state5.isLoading = false;
32923
- state5.error = `Erro ao carregar: ${error.message}`;
32924
- renderModal3(container, state5, modalId, destroy, handleSave);
32939
+ state6.isLoading = false;
32940
+ state6.error = `Erro ao carregar: ${error.message}`;
32941
+ renderModal3(container, state6, modalId, destroy, handleSave);
32925
32942
  });
32926
32943
  return { destroy };
32927
32944
  }
@@ -34191,7 +34208,7 @@ var EnergySummaryTooltip = {
34191
34208
  * RFC-0105 Enhancement: Now fetches device lists from MyIOOrchestratorData
34192
34209
  * to populate device lists for status popup display
34193
34210
  */
34194
- buildSummaryFromState(state5, receivedData, domain = "energy") {
34211
+ buildSummaryFromState(state6, receivedData, domain = "energy") {
34195
34212
  const summary = {
34196
34213
  totalDevices: 0,
34197
34214
  totalConsumption: 0,
@@ -34214,22 +34231,22 @@ var EnergySummaryTooltip = {
34214
34231
  },
34215
34232
  lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
34216
34233
  };
34217
- if (!state5) return summary;
34234
+ if (!state6) return summary;
34218
34235
  const entrada = {
34219
34236
  id: "entrada",
34220
34237
  name: "Entrada",
34221
34238
  icon: CATEGORY_ICONS.entrada,
34222
- deviceCount: state5.entrada?.devices?.length || (receivedData?.entrada_total?.device_count || 0),
34223
- consumption: state5.entrada?.total || 0,
34239
+ deviceCount: state6.entrada?.devices?.length || (receivedData?.entrada_total?.device_count || 0),
34240
+ consumption: state6.entrada?.total || 0,
34224
34241
  percentage: 100
34225
34242
  };
34226
34243
  const lojas = {
34227
34244
  id: "lojas",
34228
34245
  name: "Lojas",
34229
34246
  icon: CATEGORY_ICONS.lojas,
34230
- deviceCount: state5.consumidores?.lojas?.devices?.length || (receivedData?.lojas_total?.device_count || 0),
34231
- consumption: state5.consumidores?.lojas?.total || 0,
34232
- percentage: state5.consumidores?.lojas?.perc || 0
34247
+ deviceCount: state6.consumidores?.lojas?.devices?.length || (receivedData?.lojas_total?.device_count || 0),
34248
+ consumption: state6.consumidores?.lojas?.total || 0,
34249
+ percentage: state6.consumidores?.lojas?.perc || 0
34233
34250
  };
34234
34251
  const climatizacaoData = receivedData?.climatizacao || {};
34235
34252
  const elevadoresData = receivedData?.elevadores || {};
@@ -34240,9 +34257,9 @@ var EnergySummaryTooltip = {
34240
34257
  id: "climatizacao",
34241
34258
  name: "Climatizacao",
34242
34259
  icon: CATEGORY_ICONS.climatizacao,
34243
- deviceCount: climatizacaoData.count || state5.consumidores?.climatizacao?.devices?.length || 0,
34244
- consumption: state5.consumidores?.climatizacao?.total || 0,
34245
- percentage: state5.consumidores?.climatizacao?.perc || 0
34260
+ deviceCount: climatizacaoData.count || state6.consumidores?.climatizacao?.devices?.length || 0,
34261
+ consumption: state6.consumidores?.climatizacao?.total || 0,
34262
+ percentage: state6.consumidores?.climatizacao?.perc || 0
34246
34263
  };
34247
34264
  if (climatizacaoData.subcategories) {
34248
34265
  climatizacao.children = [];
@@ -34293,40 +34310,40 @@ var EnergySummaryTooltip = {
34293
34310
  id: "elevadores",
34294
34311
  name: "Elevadores",
34295
34312
  icon: CATEGORY_ICONS.elevadores,
34296
- deviceCount: elevadoresData.count || state5.consumidores?.elevadores?.devices?.length || 0,
34297
- consumption: state5.consumidores?.elevadores?.total || 0,
34298
- percentage: state5.consumidores?.elevadores?.perc || 0
34313
+ deviceCount: elevadoresData.count || state6.consumidores?.elevadores?.devices?.length || 0,
34314
+ consumption: state6.consumidores?.elevadores?.total || 0,
34315
+ percentage: state6.consumidores?.elevadores?.perc || 0
34299
34316
  });
34300
34317
  areaComumChildren.push({
34301
34318
  id: "escadasRolantes",
34302
34319
  name: "Esc. Rolantes",
34303
34320
  icon: CATEGORY_ICONS.escadas,
34304
- deviceCount: escadasData.count || state5.consumidores?.escadasRolantes?.devices?.length || 0,
34305
- consumption: state5.consumidores?.escadasRolantes?.total || 0,
34306
- percentage: state5.consumidores?.escadasRolantes?.perc || 0
34321
+ deviceCount: escadasData.count || state6.consumidores?.escadasRolantes?.devices?.length || 0,
34322
+ consumption: state6.consumidores?.escadasRolantes?.total || 0,
34323
+ percentage: state6.consumidores?.escadasRolantes?.perc || 0
34307
34324
  });
34308
34325
  areaComumChildren.push({
34309
34326
  id: "outros",
34310
34327
  name: "Outros",
34311
34328
  icon: CATEGORY_ICONS.outros,
34312
- deviceCount: outrosData.count || state5.consumidores?.outros?.devices?.length || 0,
34313
- consumption: state5.consumidores?.outros?.total || 0,
34314
- percentage: state5.consumidores?.outros?.perc || 0
34329
+ deviceCount: outrosData.count || state6.consumidores?.outros?.devices?.length || 0,
34330
+ consumption: state6.consumidores?.outros?.total || 0,
34331
+ percentage: state6.consumidores?.outros?.perc || 0
34315
34332
  });
34316
34333
  const areaComumDeviceCount = areaComumChildren.reduce((sum, c) => sum + c.deviceCount, 0);
34317
- const areaComumConsumption = state5.consumidores?.areaComum?.total || areaComumChildren.reduce((sum, c) => sum + c.consumption, 0);
34334
+ const areaComumConsumption = state6.consumidores?.areaComum?.total || areaComumChildren.reduce((sum, c) => sum + c.consumption, 0);
34318
34335
  const areaComum = {
34319
34336
  id: "areaComum",
34320
34337
  name: "Area Comum",
34321
34338
  icon: CATEGORY_ICONS.areaComum,
34322
34339
  deviceCount: areaComumDeviceCount,
34323
34340
  consumption: areaComumConsumption,
34324
- percentage: state5.consumidores?.areaComum?.perc || 0,
34341
+ percentage: state6.consumidores?.areaComum?.perc || 0,
34325
34342
  children: areaComumChildren
34326
34343
  };
34327
34344
  summary.byCategory = [entrada, lojas, areaComum];
34328
34345
  summary.totalDevices = entrada.deviceCount + lojas.deviceCount + areaComumDeviceCount;
34329
- summary.totalConsumption = state5.grandTotal || entrada.consumption;
34346
+ summary.totalConsumption = state6.grandTotal || entrada.consumption;
34330
34347
  const widgetAggregation = receivedData?.deviceStatusAggregation;
34331
34348
  if (widgetAggregation && widgetAggregation.hasData) {
34332
34349
  summary.byStatus = {
@@ -35614,7 +35631,7 @@ var WaterSummaryTooltip = {
35614
35631
  * RFC-0105 Enhancement: Now fetches device lists from MyIOOrchestratorData
35615
35632
  * to populate device lists for status popup display
35616
35633
  */
35617
- buildSummaryFromState(state5, receivedData, includeBathrooms = false, domain = "water") {
35634
+ buildSummaryFromState(state6, receivedData, includeBathrooms = false, domain = "water") {
35618
35635
  const summary = {
35619
35636
  totalDevices: 0,
35620
35637
  totalConsumption: 0,
@@ -35638,22 +35655,22 @@ var WaterSummaryTooltip = {
35638
35655
  lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
35639
35656
  includeBathrooms
35640
35657
  };
35641
- if (!state5) return summary;
35658
+ if (!state6) return summary;
35642
35659
  const entrada = {
35643
35660
  id: "entrada",
35644
35661
  name: "Entrada",
35645
35662
  icon: WATER_CATEGORY_ICONS.entrada,
35646
- deviceCount: state5.entrada?.devices?.length || (receivedData?.entrada_total?.device_count || 0),
35647
- consumption: state5.entrada?.total || 0,
35663
+ deviceCount: state6.entrada?.devices?.length || (receivedData?.entrada_total?.device_count || 0),
35664
+ consumption: state6.entrada?.total || 0,
35648
35665
  percentage: 100
35649
35666
  };
35650
35667
  const lojas = {
35651
35668
  id: "lojas",
35652
35669
  name: "Lojas",
35653
35670
  icon: WATER_CATEGORY_ICONS.lojas,
35654
- deviceCount: state5.lojas?.devices?.length || (receivedData?.lojas_total?.device_count || 0),
35655
- consumption: state5.lojas?.total || 0,
35656
- percentage: state5.lojas?.perc || 0
35671
+ deviceCount: state6.lojas?.devices?.length || (receivedData?.lojas_total?.device_count || 0),
35672
+ consumption: state6.lojas?.total || 0,
35673
+ percentage: state6.lojas?.perc || 0
35657
35674
  };
35658
35675
  summary.byCategory = [entrada, lojas];
35659
35676
  if (includeBathrooms) {
@@ -35661,9 +35678,9 @@ var WaterSummaryTooltip = {
35661
35678
  id: "banheiros",
35662
35679
  name: "Banheiros",
35663
35680
  icon: WATER_CATEGORY_ICONS.banheiros,
35664
- deviceCount: state5.banheiros?.devices?.length || (receivedData?.banheiros_total?.device_count || 0),
35665
- consumption: state5.banheiros?.total || 0,
35666
- percentage: state5.banheiros?.perc || 0
35681
+ deviceCount: state6.banheiros?.devices?.length || (receivedData?.banheiros_total?.device_count || 0),
35682
+ consumption: state6.banheiros?.total || 0,
35683
+ percentage: state6.banheiros?.perc || 0
35667
35684
  };
35668
35685
  summary.byCategory.push(banheiros);
35669
35686
  }
@@ -35671,24 +35688,24 @@ var WaterSummaryTooltip = {
35671
35688
  id: "areaComum",
35672
35689
  name: "\xC1rea Comum",
35673
35690
  icon: WATER_CATEGORY_ICONS.areaComum,
35674
- deviceCount: state5.areaComum?.devices?.length || (receivedData?.area_comum_total?.device_count || 0),
35675
- consumption: state5.areaComum?.total || 0,
35676
- percentage: state5.areaComum?.perc || 0
35691
+ deviceCount: state6.areaComum?.devices?.length || (receivedData?.area_comum_total?.device_count || 0),
35692
+ consumption: state6.areaComum?.total || 0,
35693
+ percentage: state6.areaComum?.perc || 0
35677
35694
  };
35678
35695
  summary.byCategory.push(areaComum);
35679
- if (state5.pontosNaoMapeados && state5.pontosNaoMapeados.total > 0) {
35696
+ if (state6.pontosNaoMapeados && state6.pontosNaoMapeados.total > 0) {
35680
35697
  const pontosNaoMapeados = {
35681
35698
  id: "pontosNaoMapeados",
35682
35699
  name: "Pontos N\xE3o Mapeados",
35683
35700
  icon: WATER_CATEGORY_ICONS.pontosNaoMapeados,
35684
- deviceCount: state5.pontosNaoMapeados?.devices?.length || 0,
35685
- consumption: state5.pontosNaoMapeados?.total || 0,
35686
- percentage: state5.pontosNaoMapeados?.perc || 0
35701
+ deviceCount: state6.pontosNaoMapeados?.devices?.length || 0,
35702
+ consumption: state6.pontosNaoMapeados?.total || 0,
35703
+ percentage: state6.pontosNaoMapeados?.perc || 0
35687
35704
  };
35688
35705
  summary.byCategory.push(pontosNaoMapeados);
35689
35706
  }
35690
35707
  summary.totalDevices = summary.byCategory.reduce((sum, cat) => sum + cat.deviceCount, 0);
35691
- summary.totalConsumption = state5.entrada?.total || 0;
35708
+ summary.totalConsumption = state6.entrada?.total || 0;
35692
35709
  const widgetAggregation = receivedData?.deviceStatusAggregation;
35693
35710
  if (widgetAggregation && widgetAggregation.hasData) {
35694
35711
  summary.byStatus = {
@@ -37225,6 +37242,996 @@ var TempSensorSummaryTooltip = {
37225
37242
  }
37226
37243
  };
37227
37244
 
37245
+ // src/utils/ContractSummaryTooltip.ts
37246
+ var CONTRACT_SUMMARY_TOOLTIP_CSS = `
37247
+ /* ============================================
37248
+ Contract Summary Tooltip (RFC-0107)
37249
+ Premium draggable tooltip with dark theme
37250
+ ============================================ */
37251
+
37252
+ .myio-contract-summary-tooltip {
37253
+ position: fixed;
37254
+ z-index: 99999;
37255
+ pointer-events: none;
37256
+ opacity: 0;
37257
+ transition: opacity 0.25s ease, transform 0.25s ease;
37258
+ transform: translateY(5px);
37259
+ }
37260
+
37261
+ .myio-contract-summary-tooltip.visible {
37262
+ opacity: 1;
37263
+ pointer-events: auto;
37264
+ transform: translateY(0);
37265
+ }
37266
+
37267
+ .myio-contract-summary-tooltip.closing {
37268
+ opacity: 0;
37269
+ transform: translateY(8px);
37270
+ transition: opacity 0.4s ease, transform 0.4s ease;
37271
+ }
37272
+
37273
+ .myio-contract-summary-tooltip.pinned {
37274
+ box-shadow: 0 0 0 2px #9684B5, 0 10px 40px rgba(0, 0, 0, 0.3);
37275
+ border-radius: 16px;
37276
+ }
37277
+
37278
+ .myio-contract-summary-tooltip.dragging {
37279
+ transition: none !important;
37280
+ cursor: move;
37281
+ }
37282
+
37283
+ .myio-contract-summary-tooltip.maximized {
37284
+ top: 20px !important;
37285
+ left: 20px !important;
37286
+ right: 20px !important;
37287
+ bottom: 20px !important;
37288
+ width: auto !important;
37289
+ max-width: none !important;
37290
+ }
37291
+
37292
+ .myio-contract-summary-tooltip.maximized .myio-contract-summary-tooltip__panel {
37293
+ width: 100%;
37294
+ height: 100%;
37295
+ max-width: none;
37296
+ display: flex;
37297
+ flex-direction: column;
37298
+ }
37299
+
37300
+ .myio-contract-summary-tooltip.maximized .myio-contract-summary-tooltip__body {
37301
+ flex: 1;
37302
+ overflow-y: auto;
37303
+ }
37304
+
37305
+ .myio-contract-summary-tooltip__panel {
37306
+ background: #2d1458;
37307
+ border: 1px solid rgba(255, 255, 255, 0.1);
37308
+ border-radius: 16px;
37309
+ box-shadow:
37310
+ 0 20px 60px rgba(0, 0, 0, 0.4),
37311
+ 0 8px 20px rgba(0, 0, 0, 0.25),
37312
+ 0 0 0 1px rgba(255, 255, 255, 0.05);
37313
+ min-width: 320px;
37314
+ max-width: 380px;
37315
+ font-family: Inter, system-ui, -apple-system, sans-serif;
37316
+ font-size: 12px;
37317
+ color: #ffffff;
37318
+ overflow: hidden;
37319
+ }
37320
+
37321
+ /* Header */
37322
+ .myio-contract-summary-tooltip__header {
37323
+ display: flex;
37324
+ align-items: center;
37325
+ gap: 10px;
37326
+ padding: 14px 16px;
37327
+ background: linear-gradient(135deg, #9684B5 0%, #2d1458 100%);
37328
+ border-radius: 16px 16px 0 0;
37329
+ position: relative;
37330
+ overflow: hidden;
37331
+ cursor: move;
37332
+ user-select: none;
37333
+ }
37334
+
37335
+ .myio-contract-summary-tooltip__header::before {
37336
+ content: '';
37337
+ position: absolute;
37338
+ top: 0;
37339
+ left: 0;
37340
+ right: 0;
37341
+ bottom: 0;
37342
+ background: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23ffffff' fill-opacity='0.05'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
37343
+ opacity: 0.3;
37344
+ }
37345
+
37346
+ .myio-contract-summary-tooltip__icon {
37347
+ width: 40px;
37348
+ height: 40px;
37349
+ background: rgba(255, 255, 255, 0.15);
37350
+ border-radius: 12px;
37351
+ display: flex;
37352
+ align-items: center;
37353
+ justify-content: center;
37354
+ font-size: 20px;
37355
+ backdrop-filter: blur(10px);
37356
+ position: relative;
37357
+ z-index: 1;
37358
+ }
37359
+
37360
+ .myio-contract-summary-tooltip__icon.valid {
37361
+ background: rgba(76, 175, 80, 0.3);
37362
+ }
37363
+
37364
+ .myio-contract-summary-tooltip__icon.invalid {
37365
+ background: rgba(244, 67, 54, 0.3);
37366
+ }
37367
+
37368
+ .myio-contract-summary-tooltip__header-info {
37369
+ flex: 1;
37370
+ position: relative;
37371
+ z-index: 1;
37372
+ }
37373
+
37374
+ .myio-contract-summary-tooltip__title {
37375
+ font-weight: 700;
37376
+ font-size: 15px;
37377
+ color: #ffffff;
37378
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
37379
+ margin-bottom: 2px;
37380
+ }
37381
+
37382
+ .myio-contract-summary-tooltip__subtitle {
37383
+ font-size: 11px;
37384
+ color: rgba(255, 255, 255, 0.7);
37385
+ }
37386
+
37387
+ .myio-contract-summary-tooltip__header-actions {
37388
+ display: flex;
37389
+ align-items: center;
37390
+ gap: 4px;
37391
+ position: relative;
37392
+ z-index: 1;
37393
+ }
37394
+
37395
+ .myio-contract-summary-tooltip__header-btn {
37396
+ width: 28px;
37397
+ height: 28px;
37398
+ border: none;
37399
+ background: rgba(255, 255, 255, 0.15);
37400
+ border-radius: 8px;
37401
+ cursor: pointer;
37402
+ display: flex;
37403
+ align-items: center;
37404
+ justify-content: center;
37405
+ transition: all 0.2s ease;
37406
+ color: rgba(255, 255, 255, 0.8);
37407
+ }
37408
+
37409
+ .myio-contract-summary-tooltip__header-btn:hover {
37410
+ background: rgba(255, 255, 255, 0.25);
37411
+ color: #ffffff;
37412
+ transform: scale(1.05);
37413
+ }
37414
+
37415
+ .myio-contract-summary-tooltip__header-btn.pinned {
37416
+ background: rgba(255, 255, 255, 0.9);
37417
+ color: #9684B5;
37418
+ }
37419
+
37420
+ .myio-contract-summary-tooltip__header-btn.pinned:hover {
37421
+ background: #ffffff;
37422
+ color: #2d1458;
37423
+ }
37424
+
37425
+ .myio-contract-summary-tooltip__header-btn svg {
37426
+ width: 14px;
37427
+ height: 14px;
37428
+ }
37429
+
37430
+ /* Body */
37431
+ .myio-contract-summary-tooltip__body {
37432
+ padding: 16px;
37433
+ }
37434
+
37435
+ /* Domain Section */
37436
+ .myio-contract-summary-tooltip__domain {
37437
+ margin-bottom: 14px;
37438
+ background: rgba(255, 255, 255, 0.05);
37439
+ border-radius: 12px;
37440
+ overflow: hidden;
37441
+ border: 1px solid rgba(255, 255, 255, 0.08);
37442
+ }
37443
+
37444
+ .myio-contract-summary-tooltip__domain:last-child {
37445
+ margin-bottom: 0;
37446
+ }
37447
+
37448
+ .myio-contract-summary-tooltip__domain-header {
37449
+ display: flex;
37450
+ align-items: center;
37451
+ justify-content: space-between;
37452
+ padding: 10px 14px;
37453
+ cursor: pointer;
37454
+ transition: background 0.2s ease;
37455
+ }
37456
+
37457
+ .myio-contract-summary-tooltip__domain-header:hover {
37458
+ background: rgba(255, 255, 255, 0.05);
37459
+ }
37460
+
37461
+ .myio-contract-summary-tooltip__domain-info {
37462
+ display: flex;
37463
+ align-items: center;
37464
+ gap: 8px;
37465
+ }
37466
+
37467
+ .myio-contract-summary-tooltip__domain-icon {
37468
+ font-size: 18px;
37469
+ }
37470
+
37471
+ .myio-contract-summary-tooltip__domain-name {
37472
+ font-weight: 600;
37473
+ font-size: 13px;
37474
+ }
37475
+
37476
+ .myio-contract-summary-tooltip__domain-count {
37477
+ font-size: 12px;
37478
+ color: #81c784;
37479
+ font-weight: 600;
37480
+ }
37481
+
37482
+ .myio-contract-summary-tooltip__expand-icon {
37483
+ font-size: 10px;
37484
+ opacity: 0.6;
37485
+ transition: transform 0.3s ease;
37486
+ }
37487
+
37488
+ .myio-contract-summary-tooltip__domain.expanded .myio-contract-summary-tooltip__expand-icon {
37489
+ transform: rotate(180deg);
37490
+ }
37491
+
37492
+ /* Domain Details */
37493
+ .myio-contract-summary-tooltip__domain-details {
37494
+ max-height: 0;
37495
+ overflow: hidden;
37496
+ transition: max-height 0.3s ease;
37497
+ background: rgba(0, 0, 0, 0.15);
37498
+ }
37499
+
37500
+ .myio-contract-summary-tooltip__domain.expanded .myio-contract-summary-tooltip__domain-details {
37501
+ max-height: 150px;
37502
+ }
37503
+
37504
+ .myio-contract-summary-tooltip__detail-row {
37505
+ display: flex;
37506
+ align-items: center;
37507
+ justify-content: space-between;
37508
+ padding: 6px 14px 6px 40px;
37509
+ font-size: 12px;
37510
+ border-top: 1px solid rgba(255, 255, 255, 0.05);
37511
+ }
37512
+
37513
+ .myio-contract-summary-tooltip__detail-row:first-child {
37514
+ border-top: none;
37515
+ }
37516
+
37517
+ .myio-contract-summary-tooltip__detail-label {
37518
+ opacity: 0.7;
37519
+ display: flex;
37520
+ align-items: center;
37521
+ gap: 6px;
37522
+ }
37523
+
37524
+ .myio-contract-summary-tooltip__detail-label::before {
37525
+ content: '';
37526
+ width: 4px;
37527
+ height: 4px;
37528
+ border-radius: 50%;
37529
+ background: currentColor;
37530
+ opacity: 0.5;
37531
+ }
37532
+
37533
+ .myio-contract-summary-tooltip__detail-count {
37534
+ font-weight: 500;
37535
+ color: #81c784;
37536
+ }
37537
+
37538
+ /* Status Banner */
37539
+ .myio-contract-summary-tooltip__status {
37540
+ display: flex;
37541
+ align-items: center;
37542
+ justify-content: center;
37543
+ gap: 8px;
37544
+ padding: 10px 14px;
37545
+ border-radius: 10px;
37546
+ margin-bottom: 14px;
37547
+ font-size: 12px;
37548
+ font-weight: 600;
37549
+ }
37550
+
37551
+ .myio-contract-summary-tooltip__status.valid {
37552
+ background: rgba(76, 175, 80, 0.2);
37553
+ color: #81c784;
37554
+ border: 1px solid rgba(76, 175, 80, 0.3);
37555
+ }
37556
+
37557
+ .myio-contract-summary-tooltip__status.invalid {
37558
+ background: rgba(244, 67, 54, 0.2);
37559
+ color: #ef5350;
37560
+ border: 1px solid rgba(244, 67, 54, 0.3);
37561
+ }
37562
+
37563
+ .myio-contract-summary-tooltip__status-icon {
37564
+ font-size: 14px;
37565
+ }
37566
+
37567
+ /* Discrepancies */
37568
+ .myio-contract-summary-tooltip__discrepancies {
37569
+ background: rgba(244, 67, 54, 0.15);
37570
+ border: 1px solid rgba(244, 67, 54, 0.3);
37571
+ border-radius: 10px;
37572
+ padding: 10px 14px;
37573
+ margin-bottom: 14px;
37574
+ }
37575
+
37576
+ .myio-contract-summary-tooltip__discrepancies-title {
37577
+ font-size: 11px;
37578
+ font-weight: 600;
37579
+ color: #ef5350;
37580
+ margin-bottom: 6px;
37581
+ text-transform: uppercase;
37582
+ letter-spacing: 0.5px;
37583
+ }
37584
+
37585
+ .myio-contract-summary-tooltip__discrepancy-item {
37586
+ font-size: 11px;
37587
+ color: rgba(255, 255, 255, 0.8);
37588
+ padding: 3px 0;
37589
+ }
37590
+
37591
+ /* Footer */
37592
+ .myio-contract-summary-tooltip__footer {
37593
+ display: flex;
37594
+ justify-content: space-between;
37595
+ align-items: center;
37596
+ padding: 12px 16px;
37597
+ background: rgba(0, 0, 0, 0.2);
37598
+ border-top: 1px solid rgba(255, 255, 255, 0.05);
37599
+ border-radius: 0 0 16px 16px;
37600
+ }
37601
+
37602
+ .myio-contract-summary-tooltip__footer-label {
37603
+ font-size: 10px;
37604
+ color: rgba(255, 255, 255, 0.5);
37605
+ }
37606
+
37607
+ .myio-contract-summary-tooltip__footer-value {
37608
+ font-size: 11px;
37609
+ font-weight: 600;
37610
+ color: rgba(255, 255, 255, 0.8);
37611
+ }
37612
+
37613
+ /* Total Devices Badge */
37614
+ .myio-contract-summary-tooltip__total {
37615
+ display: flex;
37616
+ align-items: center;
37617
+ justify-content: center;
37618
+ gap: 8px;
37619
+ padding: 12px;
37620
+ background: rgba(255, 255, 255, 0.08);
37621
+ border-radius: 10px;
37622
+ margin-bottom: 14px;
37623
+ }
37624
+
37625
+ .myio-contract-summary-tooltip__total-label {
37626
+ font-size: 12px;
37627
+ opacity: 0.8;
37628
+ }
37629
+
37630
+ .myio-contract-summary-tooltip__total-value {
37631
+ font-size: 18px;
37632
+ font-weight: 700;
37633
+ color: #81c784;
37634
+ }
37635
+
37636
+ /* Responsive */
37637
+ @media (max-width: 400px) {
37638
+ .myio-contract-summary-tooltip__panel {
37639
+ min-width: 280px;
37640
+ max-width: 95vw;
37641
+ }
37642
+ }
37643
+ `;
37644
+ var cssInjected9 = false;
37645
+ function injectCSS9() {
37646
+ if (cssInjected9) return;
37647
+ if (typeof document === "undefined") return;
37648
+ const styleId = "myio-contract-summary-tooltip-styles";
37649
+ if (document.getElementById(styleId)) {
37650
+ cssInjected9 = true;
37651
+ return;
37652
+ }
37653
+ const style = document.createElement("style");
37654
+ style.id = styleId;
37655
+ style.textContent = CONTRACT_SUMMARY_TOOLTIP_CSS;
37656
+ document.head.appendChild(style);
37657
+ cssInjected9 = true;
37658
+ }
37659
+ var state5 = {
37660
+ hideTimer: null,
37661
+ isMouseOverTooltip: false,
37662
+ isMaximized: false,
37663
+ isDragging: false,
37664
+ dragOffset: { x: 0, y: 0 },
37665
+ savedPosition: null,
37666
+ pinnedCounter: 0,
37667
+ expandedDomains: /* @__PURE__ */ new Set(["energy", "water", "temperature"])
37668
+ };
37669
+ function formatTimestamp5(isoString) {
37670
+ if (!isoString) return "Agora";
37671
+ try {
37672
+ const date = new Date(isoString);
37673
+ return date.toLocaleString("pt-BR", {
37674
+ hour: "2-digit",
37675
+ minute: "2-digit",
37676
+ day: "2-digit",
37677
+ month: "2-digit"
37678
+ });
37679
+ } catch {
37680
+ return "Agora";
37681
+ }
37682
+ }
37683
+ function calculateTotalDevices(data) {
37684
+ return data.energy.total + data.water.total + data.temperature.total;
37685
+ }
37686
+ function generateHeaderHTML5(data) {
37687
+ const iconClass = data.isValid ? "valid" : "invalid";
37688
+ const iconSymbol = data.isValid ? "\u2713" : "!";
37689
+ const totalDevices = calculateTotalDevices(data);
37690
+ return `
37691
+ <div class="myio-contract-summary-tooltip__header" data-drag-handle>
37692
+ <div class="myio-contract-summary-tooltip__icon ${iconClass}">${iconSymbol}</div>
37693
+ <div class="myio-contract-summary-tooltip__header-info">
37694
+ <div class="myio-contract-summary-tooltip__title">Contract Summary</div>
37695
+ <div class="myio-contract-summary-tooltip__subtitle">${totalDevices} devices loaded</div>
37696
+ </div>
37697
+ <div class="myio-contract-summary-tooltip__header-actions">
37698
+ <button class="myio-contract-summary-tooltip__header-btn" data-action="pin" title="Pin to screen">
37699
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
37700
+ <path d="M9 4v6l-2 4v2h10v-2l-2-4V4"/>
37701
+ <line x1="12" y1="16" x2="12" y2="21"/>
37702
+ <line x1="8" y1="4" x2="16" y2="4"/>
37703
+ </svg>
37704
+ </button>
37705
+ <button class="myio-contract-summary-tooltip__header-btn" data-action="maximize" title="Maximize">
37706
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
37707
+ <rect x="3" y="3" width="18" height="18" rx="2"/>
37708
+ </svg>
37709
+ </button>
37710
+ <button class="myio-contract-summary-tooltip__header-btn" data-action="close" title="Close">
37711
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
37712
+ <path d="M18 6L6 18M6 6l12 12"/>
37713
+ </svg>
37714
+ </button>
37715
+ </div>
37716
+ </div>
37717
+ `;
37718
+ }
37719
+ function generateDomainHTML(domain, icon, name, counts, isTemperature = false) {
37720
+ const isExpanded = state5.expandedDomains.has(domain);
37721
+ const expandedClass = isExpanded ? "expanded" : "";
37722
+ let detailsHTML = "";
37723
+ if (isTemperature) {
37724
+ const tempCounts = counts;
37725
+ detailsHTML = `
37726
+ <div class="myio-contract-summary-tooltip__detail-row">
37727
+ <span class="myio-contract-summary-tooltip__detail-label">Internal (Climate)</span>
37728
+ <span class="myio-contract-summary-tooltip__detail-count">${tempCounts.internal}</span>
37729
+ </div>
37730
+ <div class="myio-contract-summary-tooltip__detail-row">
37731
+ <span class="myio-contract-summary-tooltip__detail-label">Stores (Non-Climate)</span>
37732
+ <span class="myio-contract-summary-tooltip__detail-count">${tempCounts.stores}</span>
37733
+ </div>
37734
+ `;
37735
+ } else {
37736
+ const domainCounts = counts;
37737
+ detailsHTML = `
37738
+ <div class="myio-contract-summary-tooltip__detail-row">
37739
+ <span class="myio-contract-summary-tooltip__detail-label">Entries</span>
37740
+ <span class="myio-contract-summary-tooltip__detail-count">${domainCounts.entries}</span>
37741
+ </div>
37742
+ <div class="myio-contract-summary-tooltip__detail-row">
37743
+ <span class="myio-contract-summary-tooltip__detail-label">Common Area</span>
37744
+ <span class="myio-contract-summary-tooltip__detail-count">${domainCounts.commonArea}</span>
37745
+ </div>
37746
+ <div class="myio-contract-summary-tooltip__detail-row">
37747
+ <span class="myio-contract-summary-tooltip__detail-label">Stores</span>
37748
+ <span class="myio-contract-summary-tooltip__detail-count">${domainCounts.stores}</span>
37749
+ </div>
37750
+ `;
37751
+ }
37752
+ return `
37753
+ <div class="myio-contract-summary-tooltip__domain ${expandedClass}" data-domain="${domain}">
37754
+ <div class="myio-contract-summary-tooltip__domain-header" data-toggle-domain="${domain}">
37755
+ <div class="myio-contract-summary-tooltip__domain-info">
37756
+ <span class="myio-contract-summary-tooltip__domain-icon">${icon}</span>
37757
+ <span class="myio-contract-summary-tooltip__domain-name">${name}</span>
37758
+ </div>
37759
+ <div style="display: flex; align-items: center; gap: 8px;">
37760
+ <span class="myio-contract-summary-tooltip__domain-count">${counts.total} devices</span>
37761
+ <span class="myio-contract-summary-tooltip__expand-icon">\u25BC</span>
37762
+ </div>
37763
+ </div>
37764
+ <div class="myio-contract-summary-tooltip__domain-details">
37765
+ ${detailsHTML}
37766
+ </div>
37767
+ </div>
37768
+ `;
37769
+ }
37770
+ function generateBodyHTML3(data) {
37771
+ const totalDevices = calculateTotalDevices(data);
37772
+ const timestamp = formatTimestamp5(data.timestamp);
37773
+ const statusClass = data.isValid ? "valid" : "invalid";
37774
+ const statusIcon = data.isValid ? "\u2713" : "\u26A0";
37775
+ const statusText = data.isValid ? "Contract validated successfully" : "Validation issues detected";
37776
+ let discrepanciesHTML = "";
37777
+ if (data.discrepancies && data.discrepancies.length > 0) {
37778
+ const items = data.discrepancies.map((d) => `<div class="myio-contract-summary-tooltip__discrepancy-item">${d.domain}: expected ${d.expected}, found ${d.actual}</div>`).join("");
37779
+ discrepanciesHTML = `
37780
+ <div class="myio-contract-summary-tooltip__discrepancies">
37781
+ <div class="myio-contract-summary-tooltip__discrepancies-title">Discrepancies</div>
37782
+ ${items}
37783
+ </div>
37784
+ `;
37785
+ }
37786
+ return `
37787
+ <div class="myio-contract-summary-tooltip__body">
37788
+ <!-- Status Banner -->
37789
+ <div class="myio-contract-summary-tooltip__status ${statusClass}">
37790
+ <span class="myio-contract-summary-tooltip__status-icon">${statusIcon}</span>
37791
+ <span>${statusText}</span>
37792
+ </div>
37793
+
37794
+ ${discrepanciesHTML}
37795
+
37796
+ <!-- Total Devices -->
37797
+ <div class="myio-contract-summary-tooltip__total">
37798
+ <span class="myio-contract-summary-tooltip__total-label">Total Devices:</span>
37799
+ <span class="myio-contract-summary-tooltip__total-value">${totalDevices}</span>
37800
+ </div>
37801
+
37802
+ <!-- Energy -->
37803
+ ${generateDomainHTML("energy", "\u26A1", "Energy", data.energy)}
37804
+
37805
+ <!-- Water -->
37806
+ ${generateDomainHTML("water", "\u{1F4A7}", "Water", data.water)}
37807
+
37808
+ <!-- Temperature -->
37809
+ ${generateDomainHTML("temperature", "\u{1F321}\uFE0F", "Temperature", data.temperature, true)}
37810
+ </div>
37811
+
37812
+ <!-- Footer -->
37813
+ <div class="myio-contract-summary-tooltip__footer">
37814
+ <span class="myio-contract-summary-tooltip__footer-label">Loaded at</span>
37815
+ <span class="myio-contract-summary-tooltip__footer-value">${timestamp}</span>
37816
+ </div>
37817
+ `;
37818
+ }
37819
+ function setupHoverListeners5(container) {
37820
+ container.onmouseenter = () => {
37821
+ state5.isMouseOverTooltip = true;
37822
+ if (state5.hideTimer) {
37823
+ clearTimeout(state5.hideTimer);
37824
+ state5.hideTimer = null;
37825
+ }
37826
+ };
37827
+ container.onmouseleave = () => {
37828
+ state5.isMouseOverTooltip = false;
37829
+ startDelayedHide5();
37830
+ };
37831
+ }
37832
+ function setupDomainToggleListeners(container) {
37833
+ const toggles = container.querySelectorAll("[data-toggle-domain]");
37834
+ toggles.forEach((toggle) => {
37835
+ toggle.onclick = (e) => {
37836
+ e.stopPropagation();
37837
+ const domain = toggle.dataset.toggleDomain;
37838
+ if (!domain) return;
37839
+ const domainEl = container.querySelector(`[data-domain="${domain}"]`);
37840
+ if (!domainEl) return;
37841
+ if (state5.expandedDomains.has(domain)) {
37842
+ state5.expandedDomains.delete(domain);
37843
+ domainEl.classList.remove("expanded");
37844
+ } else {
37845
+ state5.expandedDomains.add(domain);
37846
+ domainEl.classList.add("expanded");
37847
+ }
37848
+ };
37849
+ });
37850
+ }
37851
+ function setupButtonListeners5(container) {
37852
+ const buttons = container.querySelectorAll("[data-action]");
37853
+ buttons.forEach((btn) => {
37854
+ btn.onclick = (e) => {
37855
+ e.stopPropagation();
37856
+ const action = btn.dataset.action;
37857
+ switch (action) {
37858
+ case "pin":
37859
+ createPinnedClone5(container);
37860
+ break;
37861
+ case "maximize":
37862
+ toggleMaximize5(container);
37863
+ break;
37864
+ case "close":
37865
+ ContractSummaryTooltip.close();
37866
+ break;
37867
+ }
37868
+ };
37869
+ });
37870
+ }
37871
+ function setupDragListeners5(container) {
37872
+ const header = container.querySelector("[data-drag-handle]");
37873
+ if (!header) return;
37874
+ header.onmousedown = (e) => {
37875
+ if (e.target.closest("[data-action]")) return;
37876
+ if (e.target.closest("[data-toggle-domain]")) return;
37877
+ if (state5.isMaximized) return;
37878
+ state5.isDragging = true;
37879
+ container.classList.add("dragging");
37880
+ const rect = container.getBoundingClientRect();
37881
+ state5.dragOffset = {
37882
+ x: e.clientX - rect.left,
37883
+ y: e.clientY - rect.top
37884
+ };
37885
+ const onMouseMove = (e2) => {
37886
+ if (!state5.isDragging) return;
37887
+ const newLeft = e2.clientX - state5.dragOffset.x;
37888
+ const newTop = e2.clientY - state5.dragOffset.y;
37889
+ const maxLeft = window.innerWidth - container.offsetWidth;
37890
+ const maxTop = window.innerHeight - container.offsetHeight;
37891
+ container.style.left = Math.max(0, Math.min(newLeft, maxLeft)) + "px";
37892
+ container.style.top = Math.max(0, Math.min(newTop, maxTop)) + "px";
37893
+ };
37894
+ const onMouseUp = () => {
37895
+ state5.isDragging = false;
37896
+ container.classList.remove("dragging");
37897
+ document.removeEventListener("mousemove", onMouseMove);
37898
+ document.removeEventListener("mouseup", onMouseUp);
37899
+ };
37900
+ document.addEventListener("mousemove", onMouseMove);
37901
+ document.addEventListener("mouseup", onMouseUp);
37902
+ };
37903
+ }
37904
+ function createPinnedClone5(container) {
37905
+ state5.pinnedCounter++;
37906
+ const pinnedId = `myio-contract-summary-tooltip-pinned-${state5.pinnedCounter}`;
37907
+ const clone = container.cloneNode(true);
37908
+ clone.id = pinnedId;
37909
+ clone.classList.add("pinned");
37910
+ clone.classList.remove("closing");
37911
+ const pinBtn = clone.querySelector('[data-action="pin"]');
37912
+ if (pinBtn) {
37913
+ pinBtn.classList.add("pinned");
37914
+ pinBtn.setAttribute("title", "Unpin");
37915
+ pinBtn.innerHTML = `
37916
+ <svg viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="1">
37917
+ <path d="M9 4v6l-2 4v2h10v-2l-2-4V4"/>
37918
+ <line x1="12" y1="16" x2="12" y2="21"/>
37919
+ <line x1="8" y1="4" x2="16" y2="4"/>
37920
+ </svg>
37921
+ `;
37922
+ }
37923
+ document.body.appendChild(clone);
37924
+ setupPinnedCloneListeners5(clone, pinnedId);
37925
+ ContractSummaryTooltip.hide();
37926
+ }
37927
+ function setupPinnedCloneListeners5(clone, cloneId) {
37928
+ let isMaximized = false;
37929
+ let savedPosition = null;
37930
+ const cloneExpandedDomains = new Set(state5.expandedDomains);
37931
+ const toggles = clone.querySelectorAll("[data-toggle-domain]");
37932
+ toggles.forEach((toggle) => {
37933
+ toggle.onclick = (e) => {
37934
+ e.stopPropagation();
37935
+ const domain = toggle.dataset.toggleDomain;
37936
+ if (!domain) return;
37937
+ const domainEl = clone.querySelector(`[data-domain="${domain}"]`);
37938
+ if (!domainEl) return;
37939
+ if (cloneExpandedDomains.has(domain)) {
37940
+ cloneExpandedDomains.delete(domain);
37941
+ domainEl.classList.remove("expanded");
37942
+ } else {
37943
+ cloneExpandedDomains.add(domain);
37944
+ domainEl.classList.add("expanded");
37945
+ }
37946
+ };
37947
+ });
37948
+ const pinBtn = clone.querySelector('[data-action="pin"]');
37949
+ if (pinBtn) {
37950
+ pinBtn.onclick = (e) => {
37951
+ e.stopPropagation();
37952
+ closePinnedClone5(cloneId);
37953
+ };
37954
+ }
37955
+ const closeBtn = clone.querySelector('[data-action="close"]');
37956
+ if (closeBtn) {
37957
+ closeBtn.onclick = (e) => {
37958
+ e.stopPropagation();
37959
+ closePinnedClone5(cloneId);
37960
+ };
37961
+ }
37962
+ const maxBtn = clone.querySelector('[data-action="maximize"]');
37963
+ if (maxBtn) {
37964
+ maxBtn.onclick = (e) => {
37965
+ e.stopPropagation();
37966
+ isMaximized = !isMaximized;
37967
+ if (isMaximized) {
37968
+ savedPosition = { left: clone.style.left, top: clone.style.top };
37969
+ maxBtn.innerHTML = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="5" y="5" width="14" height="14" rx="2"/><path d="M9 5V3h12v12h-2"/></svg>`;
37970
+ maxBtn.setAttribute("title", "Restore");
37971
+ } else {
37972
+ maxBtn.innerHTML = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/></svg>`;
37973
+ maxBtn.setAttribute("title", "Maximize");
37974
+ if (savedPosition) {
37975
+ clone.style.left = savedPosition.left;
37976
+ clone.style.top = savedPosition.top;
37977
+ }
37978
+ }
37979
+ clone.classList.toggle("maximized", isMaximized);
37980
+ };
37981
+ }
37982
+ const header = clone.querySelector("[data-drag-handle]");
37983
+ if (header) {
37984
+ let isDragging = false;
37985
+ let dragOffset = { x: 0, y: 0 };
37986
+ header.onmousedown = (e) => {
37987
+ if (e.target.closest("[data-action]")) return;
37988
+ if (e.target.closest("[data-toggle-domain]")) return;
37989
+ if (isMaximized) return;
37990
+ isDragging = true;
37991
+ clone.classList.add("dragging");
37992
+ const rect = clone.getBoundingClientRect();
37993
+ dragOffset = { x: e.clientX - rect.left, y: e.clientY - rect.top };
37994
+ const onMouseMove = (e2) => {
37995
+ if (!isDragging) return;
37996
+ const newLeft = e2.clientX - dragOffset.x;
37997
+ const newTop = e2.clientY - dragOffset.y;
37998
+ const maxLeft = window.innerWidth - clone.offsetWidth;
37999
+ const maxTop = window.innerHeight - clone.offsetHeight;
38000
+ clone.style.left = Math.max(0, Math.min(newLeft, maxLeft)) + "px";
38001
+ clone.style.top = Math.max(0, Math.min(newTop, maxTop)) + "px";
38002
+ };
38003
+ const onMouseUp = () => {
38004
+ isDragging = false;
38005
+ clone.classList.remove("dragging");
38006
+ document.removeEventListener("mousemove", onMouseMove);
38007
+ document.removeEventListener("mouseup", onMouseUp);
38008
+ };
38009
+ document.addEventListener("mousemove", onMouseMove);
38010
+ document.addEventListener("mouseup", onMouseUp);
38011
+ };
38012
+ }
38013
+ }
38014
+ function closePinnedClone5(cloneId) {
38015
+ const clone = document.getElementById(cloneId);
38016
+ if (clone) {
38017
+ clone.classList.add("closing");
38018
+ setTimeout(() => clone.remove(), 400);
38019
+ }
38020
+ }
38021
+ function toggleMaximize5(container) {
38022
+ state5.isMaximized = !state5.isMaximized;
38023
+ if (state5.isMaximized) {
38024
+ state5.savedPosition = {
38025
+ left: container.style.left,
38026
+ top: container.style.top
38027
+ };
38028
+ }
38029
+ container.classList.toggle("maximized", state5.isMaximized);
38030
+ const maxBtn = container.querySelector('[data-action="maximize"]');
38031
+ if (maxBtn) {
38032
+ if (state5.isMaximized) {
38033
+ maxBtn.innerHTML = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="5" y="5" width="14" height="14" rx="2"/><path d="M9 5V3h12v12h-2"/></svg>`;
38034
+ maxBtn.setAttribute("title", "Restore");
38035
+ } else {
38036
+ maxBtn.innerHTML = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/></svg>`;
38037
+ maxBtn.setAttribute("title", "Maximize");
38038
+ if (state5.savedPosition) {
38039
+ container.style.left = state5.savedPosition.left;
38040
+ container.style.top = state5.savedPosition.top;
38041
+ }
38042
+ }
38043
+ }
38044
+ }
38045
+ function startDelayedHide5() {
38046
+ if (state5.isMouseOverTooltip) return;
38047
+ if (state5.hideTimer) {
38048
+ clearTimeout(state5.hideTimer);
38049
+ }
38050
+ state5.hideTimer = setTimeout(() => {
38051
+ hideWithAnimation5();
38052
+ }, 1500);
38053
+ }
38054
+ function hideWithAnimation5() {
38055
+ const container = document.getElementById("myio-contract-summary-tooltip");
38056
+ if (container && container.classList.contains("visible")) {
38057
+ container.classList.add("closing");
38058
+ setTimeout(() => {
38059
+ container.classList.remove("visible", "closing");
38060
+ }, 400);
38061
+ }
38062
+ }
38063
+ function positionTooltip5(container, triggerElement) {
38064
+ const rect = triggerElement.getBoundingClientRect();
38065
+ let left = rect.left;
38066
+ let top = rect.bottom + 8;
38067
+ const tooltipWidth = 360;
38068
+ if (left + tooltipWidth > window.innerWidth - 20) {
38069
+ left = window.innerWidth - tooltipWidth - 20;
38070
+ }
38071
+ if (left < 10) left = 10;
38072
+ if (top + 500 > window.innerHeight) {
38073
+ top = rect.top - 8 - 500;
38074
+ if (top < 10) top = 10;
38075
+ }
38076
+ container.style.left = left + "px";
38077
+ container.style.top = top + "px";
38078
+ }
38079
+ var ContractSummaryTooltip = {
38080
+ containerId: "myio-contract-summary-tooltip",
38081
+ /**
38082
+ * Get or create container
38083
+ */
38084
+ getContainer() {
38085
+ injectCSS9();
38086
+ let container = document.getElementById(this.containerId);
38087
+ if (!container) {
38088
+ container = document.createElement("div");
38089
+ container.id = this.containerId;
38090
+ container.className = "myio-contract-summary-tooltip";
38091
+ document.body.appendChild(container);
38092
+ }
38093
+ return container;
38094
+ },
38095
+ /**
38096
+ * Show tooltip
38097
+ */
38098
+ show(triggerElement, data) {
38099
+ if (state5.hideTimer) {
38100
+ clearTimeout(state5.hideTimer);
38101
+ state5.hideTimer = null;
38102
+ }
38103
+ const container = this.getContainer();
38104
+ container.classList.remove("closing");
38105
+ container.innerHTML = `
38106
+ <div class="myio-contract-summary-tooltip__panel">
38107
+ ${generateHeaderHTML5(data)}
38108
+ ${generateBodyHTML3(data)}
38109
+ </div>
38110
+ `;
38111
+ positionTooltip5(container, triggerElement);
38112
+ container.classList.add("visible");
38113
+ setupHoverListeners5(container);
38114
+ setupButtonListeners5(container);
38115
+ setupDragListeners5(container);
38116
+ setupDomainToggleListeners(container);
38117
+ },
38118
+ /**
38119
+ * Start delayed hide
38120
+ */
38121
+ startDelayedHide() {
38122
+ startDelayedHide5();
38123
+ },
38124
+ /**
38125
+ * Hide immediately
38126
+ */
38127
+ hide() {
38128
+ if (state5.hideTimer) {
38129
+ clearTimeout(state5.hideTimer);
38130
+ state5.hideTimer = null;
38131
+ }
38132
+ state5.isMouseOverTooltip = false;
38133
+ const container = document.getElementById(this.containerId);
38134
+ if (container) {
38135
+ container.classList.remove("visible", "closing");
38136
+ }
38137
+ },
38138
+ /**
38139
+ * Close and reset all states
38140
+ */
38141
+ close() {
38142
+ state5.isMaximized = false;
38143
+ state5.isDragging = false;
38144
+ state5.savedPosition = null;
38145
+ if (state5.hideTimer) {
38146
+ clearTimeout(state5.hideTimer);
38147
+ state5.hideTimer = null;
38148
+ }
38149
+ state5.isMouseOverTooltip = false;
38150
+ const container = document.getElementById(this.containerId);
38151
+ if (container) {
38152
+ container.classList.remove("visible", "pinned", "maximized", "dragging", "closing");
38153
+ }
38154
+ },
38155
+ /**
38156
+ * Attach tooltip to trigger element with click behavior
38157
+ */
38158
+ attach(triggerElement, getDataFn) {
38159
+ const self = this;
38160
+ const handleClick = () => {
38161
+ if (state5.hideTimer) {
38162
+ clearTimeout(state5.hideTimer);
38163
+ state5.hideTimer = null;
38164
+ }
38165
+ const data = getDataFn();
38166
+ if (data) {
38167
+ self.show(triggerElement, data);
38168
+ }
38169
+ };
38170
+ triggerElement.addEventListener("click", handleClick);
38171
+ return () => {
38172
+ triggerElement.removeEventListener("click", handleClick);
38173
+ self.hide();
38174
+ };
38175
+ },
38176
+ /**
38177
+ * Attach tooltip with hover behavior
38178
+ */
38179
+ attachHover(triggerElement, getDataFn) {
38180
+ const self = this;
38181
+ const handleMouseEnter = () => {
38182
+ if (state5.hideTimer) {
38183
+ clearTimeout(state5.hideTimer);
38184
+ state5.hideTimer = null;
38185
+ }
38186
+ const data = getDataFn();
38187
+ if (data) {
38188
+ self.show(triggerElement, data);
38189
+ }
38190
+ };
38191
+ const handleMouseLeave = () => {
38192
+ startDelayedHide5();
38193
+ };
38194
+ triggerElement.addEventListener("mouseenter", handleMouseEnter);
38195
+ triggerElement.addEventListener("mouseleave", handleMouseLeave);
38196
+ return () => {
38197
+ triggerElement.removeEventListener("mouseenter", handleMouseEnter);
38198
+ triggerElement.removeEventListener("mouseleave", handleMouseLeave);
38199
+ self.hide();
38200
+ };
38201
+ },
38202
+ /**
38203
+ * Build contract data from window.CONTRACT_STATE
38204
+ * Helper method to build the data structure from global state
38205
+ */
38206
+ buildFromGlobalState() {
38207
+ const globalState = window.CONTRACT_STATE;
38208
+ if (!globalState) return null;
38209
+ return {
38210
+ isLoaded: globalState.isLoaded ?? false,
38211
+ isValid: globalState.isValid ?? false,
38212
+ timestamp: globalState.timestamp ?? null,
38213
+ energy: {
38214
+ total: globalState.energy?.total ?? 0,
38215
+ entries: globalState.energy?.entries ?? 0,
38216
+ commonArea: globalState.energy?.commonArea ?? 0,
38217
+ stores: globalState.energy?.stores ?? 0
38218
+ },
38219
+ water: {
38220
+ total: globalState.water?.total ?? 0,
38221
+ entries: globalState.water?.entries ?? 0,
38222
+ commonArea: globalState.water?.commonArea ?? 0,
38223
+ stores: globalState.water?.stores ?? 0
38224
+ },
38225
+ temperature: {
38226
+ total: globalState.temperature?.total ?? 0,
38227
+ internal: globalState.temperature?.internal ?? 0,
38228
+ stores: globalState.temperature?.stores ?? 0
38229
+ },
38230
+ discrepancies: globalState.discrepancies
38231
+ };
38232
+ }
38233
+ };
38234
+
37228
38235
  // src/components/ModalHeader/index.ts
37229
38236
  var DEFAULT_BG_COLOR = "#3e1a7d";
37230
38237
  var DEFAULT_TEXT_COLOR = "white";
@@ -40988,6 +41995,7 @@ export {
40988
41995
  DEFAULT_CONFIG as CONSUMPTION_CHART_DEFAULTS,
40989
41996
  THEME_COLORS as CONSUMPTION_THEME_COLORS,
40990
41997
  ConnectionStatusType,
41998
+ ContractSummaryTooltip,
40991
41999
  DEFAULT_CLAMP_RANGE,
40992
42000
  DEFAULT_ENERGY_GROUP_COLORS,
40993
42001
  DEFAULT_GAS_GROUP_COLORS,