myio-js-library 0.1.174 → 0.1.179

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -5620,6 +5620,16 @@ function formatValueByDomain(value, domain) {
5620
5620
  }
5621
5621
  return formatEnergy(value);
5622
5622
  }
5623
+ function formatRelativeTime2(timestamp) {
5624
+ if (!timestamp || isNaN(timestamp)) return "\u2014";
5625
+ const date = new Date(timestamp);
5626
+ const hours = String(date.getHours()).padStart(2, "0");
5627
+ const minutes = String(date.getMinutes()).padStart(2, "0");
5628
+ const day = String(date.getDate()).padStart(2, "0");
5629
+ const month = String(date.getMonth() + 1).padStart(2, "0");
5630
+ const year = date.getFullYear();
5631
+ return `${hours}:${minutes} ${day}/${month}/${year}`;
5632
+ }
5623
5633
  function calculateConsumptionPercentage(target, consumption) {
5624
5634
  const numericTarget = Number(target);
5625
5635
  const numericConsumption = Number(consumption);
@@ -5872,6 +5882,8 @@ function buildDOM(state) {
5872
5882
  powerLabel.className = "label";
5873
5883
  if (entityObject.domain === "water") {
5874
5884
  powerLabel.textContent = "Leitura";
5885
+ } else if (entityObject.domain === "temperature") {
5886
+ powerLabel.textContent = "\xDAlt. Telemetria";
5875
5887
  } else {
5876
5888
  powerLabel.textContent = i18n.instantaneous_power || "Pot\xEAncia";
5877
5889
  }
@@ -6125,14 +6137,24 @@ function paint(root, state) {
6125
6137
  effContainer.style.display = "none";
6126
6138
  }
6127
6139
  const opTimeVal = root.querySelector(".myio-ho-card__footer .metric:nth-child(1) .val");
6140
+ const opTimeLabel = root.querySelector(".myio-ho-card__footer .metric:nth-child(1) .label");
6128
6141
  if (opTimeVal) {
6129
- opTimeVal.textContent = entityObject.operationHours ?? "-";
6142
+ if (entityObject.domain === "temperature") {
6143
+ if (opTimeLabel) opTimeLabel.textContent = "Temp. Atual";
6144
+ const currentTemp = entityObject.currentTemperature ?? entityObject.temperature ?? entityObject.val ?? null;
6145
+ opTimeVal.textContent = currentTemp !== null ? `${Number(currentTemp).toFixed(1)}\xB0C` : "-";
6146
+ } else {
6147
+ if (opTimeLabel) opTimeLabel.textContent = i18n.operation_time;
6148
+ opTimeVal.textContent = entityObject.operationHours ?? "-";
6149
+ }
6130
6150
  }
6131
6151
  const powerVal = root.querySelector(".myio-ho-card__footer .metric:nth-child(2) .val");
6132
6152
  if (powerVal) {
6133
6153
  if (entityObject.domain === "water") {
6134
6154
  const pulses = entityObject.pulses ?? 0;
6135
6155
  powerVal.textContent = `${pulses} L`;
6156
+ } else if (entityObject.domain === "temperature") {
6157
+ powerVal.textContent = entityObject.lastActivityTime ? formatRelativeTime2(entityObject.lastActivityTime) : "-";
6136
6158
  } else {
6137
6159
  const instantPower = entityObject.instantaneousPower ?? entityObject.consumption_power ?? null;
6138
6160
  const powerFormatted = formatPower(instantPower);
@@ -16785,35 +16807,72 @@ function validateOptions2(options) {
16785
16807
  }
16786
16808
 
16787
16809
  // src/components/premium-modals/power-limits/types.ts
16810
+ var DOMAINS = [
16811
+ { value: "energy", label: "Energia", icon: "\u26A1" },
16812
+ { value: "water", label: "\xC1gua", icon: "\u{1F4A7}" },
16813
+ { value: "temperature", label: "Temperatura", icon: "\u{1F321}\uFE0F" }
16814
+ ];
16788
16815
  var DEVICE_TYPES = [
16789
- { value: "ELEVADOR", label: "Elevator" },
16790
- { value: "ESCADA_ROLANTE", label: "Escalator" },
16816
+ { value: "ELEVADOR", label: "Elevador" },
16817
+ { value: "ESCADA_ROLANTE", label: "Escada Rolante" },
16791
16818
  { value: "MOTOR", label: "Motor" },
16792
- { value: "BOMBA", label: "Pump" },
16819
+ { value: "BOMBA", label: "Bomba" },
16793
16820
  { value: "CHILLER", label: "Chiller" },
16794
- { value: "AR_CONDICIONADO", label: "Air Conditioner" },
16821
+ { value: "AR_CONDICIONADO", label: "Ar Condicionado" },
16795
16822
  { value: "HVAC", label: "HVAC" },
16796
16823
  { value: "FANCOIL", label: "Fancoil" },
16797
- { value: "3F_MEDIDOR", label: "Three-phase Meter" }
16824
+ { value: "3F_MEDIDOR", label: "Medidor Trif\xE1sico" }
16798
16825
  ];
16799
16826
  var TELEMETRY_TYPES2 = [
16800
- { value: "consumption", label: "Consumption (kW)", unit: "kW" },
16801
- { value: "voltage_a", label: "Voltage A (V)", unit: "V" },
16802
- { value: "voltage_b", label: "Voltage B (V)", unit: "V" },
16803
- { value: "voltage_c", label: "Voltage C (V)", unit: "V" },
16804
- { value: "current_a", label: "Current A (A)", unit: "A" },
16805
- { value: "current_b", label: "Current B (A)", unit: "A" },
16806
- { value: "current_c", label: "Current C (A)", unit: "A" },
16807
- { value: "total_current", label: "Total Current (A)", unit: "A" },
16808
- { value: "fp_a", label: "Power Factor A", unit: "" },
16809
- { value: "fp_b", label: "Power Factor B", unit: "" },
16810
- { value: "fp_c", label: "Power Factor C", unit: "" }
16827
+ { value: "consumption", label: "Pot\xEAncia (kW)", unit: "kW" },
16828
+ { value: "voltage_a", label: "Tens\xE3o A (V)", unit: "V" },
16829
+ { value: "voltage_b", label: "Tens\xE3o B (V)", unit: "V" },
16830
+ { value: "voltage_c", label: "Tens\xE3o C (V)", unit: "V" },
16831
+ { value: "current_a", label: "Corrente A (A)", unit: "A" },
16832
+ { value: "current_b", label: "Corrente B (A)", unit: "A" },
16833
+ { value: "current_c", label: "Corrente C (A)", unit: "A" },
16834
+ { value: "total_current", label: "Corrente Total (A)", unit: "A" },
16835
+ { value: "fp_a", label: "Fator de Pot\xEAncia A", unit: "" },
16836
+ { value: "fp_b", label: "Fator de Pot\xEAncia B", unit: "" },
16837
+ { value: "fp_c", label: "Fator de Pot\xEAncia C", unit: "" }
16811
16838
  ];
16839
+ var STATUS_ICONS = {
16840
+ energy: {
16841
+ standBy: "\u{1F50C}",
16842
+ // STANDBY
16843
+ normal: "\u26A1",
16844
+ // POWER_ON
16845
+ alert: "\u26A0\uFE0F",
16846
+ // WARNING
16847
+ failure: "\u{1F6A8}"
16848
+ // FAILURE
16849
+ },
16850
+ water: {
16851
+ standBy: "\u{1F6B0}",
16852
+ // STANDBY
16853
+ normal: "\u{1F4A7}",
16854
+ // POWER_ON
16855
+ alert: "\u26A0\uFE0F",
16856
+ // WARNING
16857
+ failure: "\u{1F6A8}"
16858
+ // FAILURE
16859
+ },
16860
+ temperature: {
16861
+ standBy: "\u{1F321}\uFE0F",
16862
+ // STANDBY
16863
+ normal: "\u{1F321}\uFE0F",
16864
+ // POWER_ON
16865
+ alert: "\u26A0\uFE0F",
16866
+ // WARNING
16867
+ failure: "\u{1F6A8}"
16868
+ // FAILURE
16869
+ }
16870
+ };
16812
16871
  var STATUS_CONFIG = {
16813
16872
  standBy: { label: "StandBy", color: "#22c55e", bgColor: "rgba(34, 197, 94, 0.1)" },
16814
16873
  normal: { label: "Normal", color: "#3b82f6", bgColor: "rgba(59, 130, 246, 0.1)" },
16815
- alert: { label: "Alert", color: "#f59e0b", bgColor: "rgba(245, 158, 11, 0.1)" },
16816
- failure: { label: "Failure", color: "#ef4444", bgColor: "rgba(239, 68, 68, 0.1)" }
16874
+ alert: { label: "Alerta", color: "#f59e0b", bgColor: "rgba(245, 158, 11, 0.1)" },
16875
+ failure: { label: "Falha", color: "#ef4444", bgColor: "rgba(239, 68, 68, 0.1)" }
16817
16876
  };
16818
16877
 
16819
16878
  // src/components/premium-modals/power-limits/PowerLimitsModalView.ts
@@ -16829,12 +16888,43 @@ var PowerLimitsModalView = class {
16829
16888
  this.formData = {
16830
16889
  deviceType: config.deviceType,
16831
16890
  telemetryType: config.telemetryType,
16891
+ domain: config.domain,
16832
16892
  standby: { baseValue: null, topValue: null },
16833
16893
  normal: { baseValue: null, topValue: null },
16834
16894
  alert: { baseValue: null, topValue: null },
16835
16895
  failure: { baseValue: null, topValue: null }
16836
16896
  };
16837
16897
  }
16898
+ // Format number with thousand separator (.) and up to 2 decimal places
16899
+ formatNumberForDisplay(value) {
16900
+ if (value === null || value === void 0) return "";
16901
+ const parts = value.toFixed(2).split(".");
16902
+ parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ".");
16903
+ return parts.join(",");
16904
+ }
16905
+ // Parse formatted string back to number
16906
+ parseFormattedNumber(value) {
16907
+ if (!value || value.trim() === "") return null;
16908
+ const normalized = value.replace(/\./g, "").replace(",", ".");
16909
+ const num = parseFloat(normalized);
16910
+ return isNaN(num) ? null : num;
16911
+ }
16912
+ // Handle input formatting on blur
16913
+ formatInputValue(input) {
16914
+ const rawValue = input.value;
16915
+ const parsed = this.parseFormattedNumber(rawValue);
16916
+ if (parsed !== null) {
16917
+ input.value = this.formatNumberForDisplay(parsed);
16918
+ }
16919
+ }
16920
+ // Handle input on focus - show raw value for editing
16921
+ unformatInputValue(input) {
16922
+ const formatted = input.value;
16923
+ const parsed = this.parseFormattedNumber(formatted);
16924
+ if (parsed !== null) {
16925
+ input.value = parsed.toString().replace(".", ",");
16926
+ }
16927
+ }
16838
16928
  render(targetContainer) {
16839
16929
  this.overlayEl = document.createElement("div");
16840
16930
  this.overlayEl.className = "myio-power-limits-overlay";
@@ -16844,6 +16934,7 @@ var PowerLimitsModalView = class {
16844
16934
  ${this.renderHeader()}
16845
16935
  ${this.renderSelectors()}
16846
16936
  ${this.renderStatusCards()}
16937
+ ${this.renderToolbar()}
16847
16938
  ${this.renderLoadingState()}
16848
16939
  ${this.renderErrorState()}
16849
16940
  ${this.renderSuccessState()}
@@ -16860,80 +16951,107 @@ var PowerLimitsModalView = class {
16860
16951
  }
16861
16952
  renderHeader() {
16862
16953
  return `
16863
- <div class="myio-power-limits-header">
16864
- <div class="myio-power-limits-title-section">
16865
- <span class="myio-power-limits-icon">&#x2699;</span>
16866
- <h2 class="myio-power-limits-title">Power Limits Setup</h2>
16867
- </div>
16868
- <div class="myio-power-limits-actions">
16954
+ <div class="myio-modal-header">
16955
+ <h2 class="myio-modal-title">\u2699\uFE0F Configura\xE7\xE3o de Limites</h2>
16956
+ <button class="myio-modal-close" id="plm-close-btn" type="button" aria-label="Fechar modal">\xD7</button>
16957
+ </div>
16958
+ `;
16959
+ }
16960
+ renderToolbar() {
16961
+ return `
16962
+ <div class="myio-power-limits-toolbar">
16963
+ <div class="myio-toolbar-actions">
16964
+ <button class="myio-btn myio-btn-secondary" id="plm-reset-btn" type="button">Limpar</button>
16869
16965
  <button class="myio-btn myio-btn-primary" id="plm-save-btn" type="button">
16870
- <span class="myio-btn-text">Save</span>
16966
+ <span class="myio-btn-text">Salvar</span>
16871
16967
  <span class="myio-btn-spinner" style="display: none;"></span>
16872
16968
  </button>
16873
- <button class="myio-btn myio-btn-secondary" id="plm-reset-btn" type="button">Reset</button>
16874
- <button class="myio-btn myio-btn-close" id="plm-close-btn" type="button" aria-label="Close">&times;</button>
16875
16969
  </div>
16876
16970
  </div>
16877
16971
  `;
16878
16972
  }
16879
16973
  renderSelectors() {
16880
- const deviceOptions = DEVICE_TYPES.map(
16881
- (dt) => `<option value="${dt.value}" ${dt.value === this.config.deviceType ? "selected" : ""}>${dt.label}</option>`
16882
- ).join("");
16883
- const telemetryOptions = TELEMETRY_TYPES2.map(
16884
- (tt) => `<option value="${tt.value}" ${tt.value === this.config.telemetryType ? "selected" : ""}>${tt.label}</option>`
16974
+ const domain = this.formData.domain || "energy";
16975
+ const domainOptions = DOMAINS.map(
16976
+ (d) => `<option value="${d.value}" ${d.value === domain ? "selected" : ""}>${d.icon} ${d.label}</option>`
16885
16977
  ).join("");
16978
+ let deviceTypeContent;
16979
+ let telemetryLabel;
16980
+ switch (domain) {
16981
+ case "temperature":
16982
+ deviceTypeContent = `<div class="myio-fixed-value">Sensor de Temperatura</div>`;
16983
+ telemetryLabel = "Temperatura em Celsius";
16984
+ break;
16985
+ case "water":
16986
+ deviceTypeContent = `<div class="myio-fixed-value">Hidr\xF4metro</div>`;
16987
+ telemetryLabel = "Litros";
16988
+ break;
16989
+ case "energy":
16990
+ default:
16991
+ deviceTypeContent = `<select id="plm-device-type" class="myio-select">
16992
+ ${DEVICE_TYPES.map(
16993
+ (dt) => `<option value="${dt.value}" ${dt.value === this.formData.deviceType ? "selected" : ""}>${dt.label}</option>`
16994
+ ).join("")}
16995
+ </select>`;
16996
+ telemetryLabel = "Pot\xEAncia (kW)";
16997
+ break;
16998
+ }
16886
16999
  return `
16887
17000
  <div class="myio-power-limits-selectors">
16888
17001
  <div class="myio-form-group">
16889
- <label for="plm-device-type">Device Type</label>
16890
- <select id="plm-device-type" class="myio-select">
16891
- ${deviceOptions}
17002
+ <label for="plm-domain">Dom\xEDnio</label>
17003
+ <select id="plm-domain" class="myio-select">
17004
+ ${domainOptions}
16892
17005
  </select>
16893
17006
  </div>
16894
17007
  <div class="myio-form-group">
16895
- <label for="plm-telemetry-type">Telemetry Type</label>
16896
- <select id="plm-telemetry-type" class="myio-select">
16897
- ${telemetryOptions}
16898
- </select>
17008
+ <label>Tipo de Dispositivo</label>
17009
+ ${deviceTypeContent}
17010
+ </div>
17011
+ <div class="myio-form-group">
17012
+ <label>Tipo de Telemetria</label>
17013
+ <div class="myio-fixed-value">${telemetryLabel}</div>
16899
17014
  </div>
16900
17015
  </div>
16901
17016
  `;
16902
17017
  }
16903
17018
  renderStatusCards() {
16904
17019
  const statuses = ["standby", "normal", "alert", "failure"];
17020
+ const domain = this.formData.domain || "energy";
17021
+ const domainIcons = STATUS_ICONS[domain];
16905
17022
  const cards = statuses.map((status) => {
16906
- const config = STATUS_CONFIG[status === "standby" ? "standBy" : status];
17023
+ const statusKey = status === "standby" ? "standBy" : status;
17024
+ const config = STATUS_CONFIG[statusKey];
16907
17025
  const formValues = this.formData[status];
17026
+ const icon = domainIcons[statusKey];
16908
17027
  return `
16909
17028
  <div class="myio-power-limits-card-item myio-status-${status}" style="--status-color: ${config.color}; --status-bg: ${config.bgColor};">
16910
17029
  <div class="myio-card-header">
17030
+ <span class="myio-status-icon">${icon}</span>
16911
17031
  <span class="myio-status-indicator"></span>
16912
17032
  <span class="myio-status-label">${config.label}</span>
16913
17033
  </div>
16914
17034
  <div class="myio-card-inputs">
16915
17035
  <div class="myio-input-group">
16916
- <label for="plm-${status}-base">Base Value</label>
17036
+ <label for="plm-${status}-base">Limite Inferior</label>
16917
17037
  <input
16918
- type="number"
17038
+ type="text"
16919
17039
  id="plm-${status}-base"
16920
- class="myio-input"
16921
- min="0"
16922
- step="0.01"
16923
- value="${formValues.baseValue ?? ""}"
16924
- placeholder="0"
17040
+ class="myio-input myio-formatted-number"
17041
+ inputmode="decimal"
17042
+ value="${this.formatNumberForDisplay(formValues.baseValue)}"
17043
+ placeholder="0,00"
16925
17044
  >
16926
17045
  </div>
16927
17046
  <div class="myio-input-group">
16928
- <label for="plm-${status}-top">Top Value</label>
17047
+ <label for="plm-${status}-top">Limite Superior</label>
16929
17048
  <input
16930
- type="number"
17049
+ type="text"
16931
17050
  id="plm-${status}-top"
16932
- class="myio-input"
16933
- min="0"
16934
- step="0.01"
16935
- value="${formValues.topValue ?? ""}"
16936
- placeholder="0"
17051
+ class="myio-input myio-formatted-number"
17052
+ inputmode="decimal"
17053
+ value="${this.formatNumberForDisplay(formValues.topValue)}"
17054
+ placeholder="0,00"
16937
17055
  >
16938
17056
  </div>
16939
17057
  </div>
@@ -16950,7 +17068,7 @@ var PowerLimitsModalView = class {
16950
17068
  return `
16951
17069
  <div class="myio-power-limits-loading" id="plm-loading" style="display: none;">
16952
17070
  <div class="myio-spinner"></div>
16953
- <span>Loading configuration...</span>
17071
+ <span>Carregando configura\xE7\xE3o...</span>
16954
17072
  </div>
16955
17073
  `;
16956
17074
  }
@@ -16966,7 +17084,7 @@ var PowerLimitsModalView = class {
16966
17084
  return `
16967
17085
  <div class="myio-power-limits-success" id="plm-success" style="display: none;">
16968
17086
  <span class="myio-success-icon">&#x2713;</span>
16969
- <span class="myio-success-message">Configuration saved successfully!</span>
17087
+ <span class="myio-success-message">Configura\xE7\xE3o salva com sucesso!</span>
16970
17088
  </div>
16971
17089
  `;
16972
17090
  }
@@ -16984,31 +17102,121 @@ var PowerLimitsModalView = class {
16984
17102
  saveBtn?.addEventListener("click", () => this.handleSave());
16985
17103
  const resetBtn = this.overlayEl.querySelector("#plm-reset-btn");
16986
17104
  resetBtn?.addEventListener("click", () => this.handleReset());
16987
- const deviceSelect = this.overlayEl.querySelector("#plm-device-type");
16988
- deviceSelect?.addEventListener("change", (e) => {
16989
- const value = e.target.value;
16990
- this.formData.deviceType = value;
16991
- this.config.onDeviceTypeChange(value);
16992
- });
16993
- const telemetrySelect = this.overlayEl.querySelector("#plm-telemetry-type");
16994
- telemetrySelect?.addEventListener("change", (e) => {
17105
+ const domainSelect = this.overlayEl.querySelector("#plm-domain");
17106
+ domainSelect?.addEventListener("change", (e) => {
16995
17107
  const value = e.target.value;
16996
- this.formData.telemetryType = value;
16997
- this.config.onTelemetryTypeChange(value);
17108
+ this.formData.domain = value;
17109
+ switch (value) {
17110
+ case "temperature":
17111
+ this.formData.deviceType = "SENSOR_TEMPERATURA";
17112
+ this.formData.telemetryType = "temperature";
17113
+ break;
17114
+ case "water":
17115
+ this.formData.deviceType = "HIDROMETRO";
17116
+ this.formData.telemetryType = "liters";
17117
+ break;
17118
+ case "energy":
17119
+ default:
17120
+ this.formData.telemetryType = "consumption";
17121
+ break;
17122
+ }
17123
+ this.config.onDomainChange(value);
17124
+ this.updateSelectorsUI();
17125
+ this.updateStatusIcons();
16998
17126
  });
17127
+ this.setupDeviceTypeListener();
16999
17128
  const statuses = ["standby", "normal", "alert", "failure"];
17000
17129
  statuses.forEach((status) => {
17001
17130
  const baseInput = this.overlayEl?.querySelector(`#plm-${status}-base`);
17002
17131
  const topInput = this.overlayEl?.querySelector(`#plm-${status}-top`);
17003
- baseInput?.addEventListener("input", (e) => {
17132
+ if (baseInput) {
17133
+ baseInput.addEventListener("focus", () => this.unformatInputValue(baseInput));
17134
+ baseInput.addEventListener("blur", () => {
17135
+ this.formData[status].baseValue = this.parseFormattedNumber(baseInput.value);
17136
+ this.formatInputValue(baseInput);
17137
+ });
17138
+ baseInput.addEventListener("keydown", (e) => this.handleNumberKeydown(e));
17139
+ }
17140
+ if (topInput) {
17141
+ topInput.addEventListener("focus", () => this.unformatInputValue(topInput));
17142
+ topInput.addEventListener("blur", () => {
17143
+ this.formData[status].topValue = this.parseFormattedNumber(topInput.value);
17144
+ this.formatInputValue(topInput);
17145
+ });
17146
+ topInput.addEventListener("keydown", (e) => this.handleNumberKeydown(e));
17147
+ }
17148
+ });
17149
+ }
17150
+ // Handle keyboard input to allow only valid number characters
17151
+ handleNumberKeydown(e) {
17152
+ const allowedKeys = ["Backspace", "Delete", "ArrowLeft", "ArrowRight", "Tab", "Home", "End"];
17153
+ const isDigit = /^\d$/.test(e.key);
17154
+ const isComma = e.key === ",";
17155
+ const isAllowedKey = allowedKeys.includes(e.key);
17156
+ const hasCtrl = e.ctrlKey || e.metaKey;
17157
+ if (!isDigit && !isComma && !isAllowedKey && !hasCtrl) {
17158
+ e.preventDefault();
17159
+ }
17160
+ if (isComma) {
17161
+ const input = e.target;
17162
+ if (input.value.includes(",")) {
17163
+ e.preventDefault();
17164
+ }
17165
+ }
17166
+ }
17167
+ // Update status icons when domain changes
17168
+ updateStatusIcons() {
17169
+ const domain = this.formData.domain || "energy";
17170
+ const domainIcons = STATUS_ICONS[domain];
17171
+ const statuses = ["standby", "normal", "alert", "failure"];
17172
+ statuses.forEach((status) => {
17173
+ const statusKey = status === "standby" ? "standBy" : status;
17174
+ const iconEl = this.overlayEl?.querySelector(`.myio-status-${status} .myio-status-icon`);
17175
+ if (iconEl) {
17176
+ iconEl.textContent = domainIcons[statusKey];
17177
+ }
17178
+ });
17179
+ }
17180
+ // Update selectors UI when domain changes
17181
+ updateSelectorsUI() {
17182
+ const selectorsContainer = this.overlayEl?.querySelector(".myio-power-limits-selectors");
17183
+ if (selectorsContainer) {
17184
+ selectorsContainer.outerHTML = this.renderSelectors();
17185
+ const domainSelect = this.overlayEl?.querySelector("#plm-domain");
17186
+ domainSelect?.addEventListener("change", (e) => {
17004
17187
  const value = e.target.value;
17005
- this.formData[status].baseValue = value ? parseFloat(value) : null;
17188
+ this.formData.domain = value;
17189
+ switch (value) {
17190
+ case "temperature":
17191
+ this.formData.deviceType = "SENSOR_TEMPERATURA";
17192
+ this.formData.telemetryType = "temperature";
17193
+ break;
17194
+ case "water":
17195
+ this.formData.deviceType = "HIDROMETRO";
17196
+ this.formData.telemetryType = "liters";
17197
+ break;
17198
+ case "energy":
17199
+ default:
17200
+ this.formData.telemetryType = "consumption";
17201
+ break;
17202
+ }
17203
+ this.config.onDomainChange(value);
17204
+ this.updateSelectorsUI();
17205
+ this.updateStatusIcons();
17006
17206
  });
17007
- topInput?.addEventListener("input", (e) => {
17207
+ this.setupDeviceTypeListener();
17208
+ }
17209
+ }
17210
+ // Setup device type listener (only for energy/water domains)
17211
+ setupDeviceTypeListener() {
17212
+ const deviceSelect = this.overlayEl?.querySelector("#plm-device-type");
17213
+ if (deviceSelect) {
17214
+ deviceSelect.addEventListener("change", (e) => {
17008
17215
  const value = e.target.value;
17009
- this.formData[status].topValue = value ? parseFloat(value) : null;
17216
+ this.formData.deviceType = value;
17217
+ this.config.onDeviceTypeChange(value);
17010
17218
  });
17011
- });
17219
+ }
17012
17220
  }
17013
17221
  handleKeyDown = (e) => {
17014
17222
  if (e.key === "Escape") {
@@ -17031,7 +17239,7 @@ var PowerLimitsModalView = class {
17031
17239
  this.showSuccess();
17032
17240
  setTimeout(() => this.hideSuccess(), 3e3);
17033
17241
  } catch (error) {
17034
- this.showError(error.message || "Failed to save configuration");
17242
+ this.showError(error.message || "Falha ao salvar configura\xE7\xE3o");
17035
17243
  } finally {
17036
17244
  this.isSaving = false;
17037
17245
  this.showSaveLoading(false);
@@ -17055,13 +17263,13 @@ var PowerLimitsModalView = class {
17055
17263
  const base = this.formData[status].baseValue;
17056
17264
  const top = this.formData[status].topValue;
17057
17265
  if (base !== null && base < 0) {
17058
- return `${STATUS_CONFIG[status === "standby" ? "standBy" : status].label}: Base value cannot be negative`;
17266
+ return `${STATUS_CONFIG[status === "standby" ? "standBy" : status].label}: Limite inferior n\xE3o pode ser negativo`;
17059
17267
  }
17060
17268
  if (top !== null && top < 0) {
17061
- return `${STATUS_CONFIG[status === "standby" ? "standBy" : status].label}: Top value cannot be negative`;
17269
+ return `${STATUS_CONFIG[status === "standby" ? "standBy" : status].label}: Limite superior n\xE3o pode ser negativo`;
17062
17270
  }
17063
17271
  if (base !== null && top !== null && base > top) {
17064
- return `${STATUS_CONFIG[status === "standby" ? "standBy" : status].label}: Base value should not exceed top value`;
17272
+ return `${STATUS_CONFIG[status === "standby" ? "standBy" : status].label}: Limite inferior n\xE3o pode ser maior que o limite superior`;
17065
17273
  }
17066
17274
  }
17067
17275
  return null;
@@ -17130,11 +17338,13 @@ var PowerLimitsModalView = class {
17130
17338
  setFormData(data) {
17131
17339
  if (data.deviceType) this.formData.deviceType = data.deviceType;
17132
17340
  if (data.telemetryType) this.formData.telemetryType = data.telemetryType;
17341
+ if (data.domain) this.formData.domain = data.domain;
17133
17342
  if (data.standby) this.formData.standby = { ...data.standby };
17134
17343
  if (data.normal) this.formData.normal = { ...data.normal };
17135
17344
  if (data.alert) this.formData.alert = { ...data.alert };
17136
17345
  if (data.failure) this.formData.failure = { ...data.failure };
17137
17346
  this.updateInputValues();
17347
+ this.updateStatusIcons();
17138
17348
  }
17139
17349
  updateInputValues() {
17140
17350
  const statuses = ["standby", "normal", "alert", "failure"];
@@ -17142,16 +17352,16 @@ var PowerLimitsModalView = class {
17142
17352
  const baseInput = this.overlayEl?.querySelector(`#plm-${status}-base`);
17143
17353
  const topInput = this.overlayEl?.querySelector(`#plm-${status}-top`);
17144
17354
  if (baseInput) {
17145
- baseInput.value = this.formData[status].baseValue?.toString() ?? "";
17355
+ baseInput.value = this.formatNumberForDisplay(this.formData[status].baseValue);
17146
17356
  }
17147
17357
  if (topInput) {
17148
- topInput.value = this.formData[status].topValue?.toString() ?? "";
17358
+ topInput.value = this.formatNumberForDisplay(this.formData[status].topValue);
17149
17359
  }
17150
17360
  });
17361
+ const domainSelect = this.overlayEl?.querySelector("#plm-domain");
17151
17362
  const deviceSelect = this.overlayEl?.querySelector("#plm-device-type");
17152
- const telemetrySelect = this.overlayEl?.querySelector("#plm-telemetry-type");
17363
+ if (domainSelect) domainSelect.value = this.formData.domain;
17153
17364
  if (deviceSelect) deviceSelect.value = this.formData.deviceType;
17154
- if (telemetrySelect) telemetrySelect.value = this.formData.telemetryType;
17155
17365
  }
17156
17366
  getStyles() {
17157
17367
  const styles = this.config.styles || {};
@@ -17175,7 +17385,7 @@ var PowerLimitsModalView = class {
17175
17385
  opacity: 0;
17176
17386
  visibility: hidden;
17177
17387
  transition: all 0.3s ease;
17178
- font-family: ${styles.fontFamily || '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'};
17388
+ font-family: ${styles.fontFamily || "'Roboto', Arial, sans-serif"};
17179
17389
  }
17180
17390
 
17181
17391
  .myio-power-limits-overlay.active {
@@ -17185,9 +17395,9 @@ var PowerLimitsModalView = class {
17185
17395
 
17186
17396
  .myio-power-limits-card {
17187
17397
  background: ${styles.backgroundColor || "#ffffff"};
17188
- border-radius: ${styles.borderRadius || "12px"};
17398
+ border-radius: ${styles.borderRadius || "10px"};
17189
17399
  width: 90%;
17190
- max-width: 875px;
17400
+ max-width: 1104px;
17191
17401
  max-height: 90vh;
17192
17402
  overflow-y: auto;
17193
17403
  transform: scale(0.9);
@@ -17199,36 +17409,55 @@ var PowerLimitsModalView = class {
17199
17409
  transform: scale(1);
17200
17410
  }
17201
17411
 
17202
- .myio-power-limits-header {
17412
+ /* Header - ModalPremiumShell pattern */
17413
+ .myio-modal-header {
17203
17414
  display: flex;
17204
17415
  align-items: center;
17205
17416
  justify-content: space-between;
17206
- padding: 20px 24px;
17207
- background: linear-gradient(135deg, ${primaryColor}, ${this.lightenColor(primaryColor, 20)});
17208
- color: white;
17209
- border-radius: 12px 12px 0 0;
17417
+ padding: 4px 8px;
17418
+ background: ${primaryColor};
17419
+ border-radius: 10px 10px 0 0;
17420
+ min-height: 20px;
17210
17421
  }
17211
17422
 
17212
- .myio-power-limits-title-section {
17213
- display: flex;
17214
- align-items: center;
17215
- gap: 12px;
17423
+ .myio-modal-title {
17424
+ margin: 6px;
17425
+ font-size: 18px;
17426
+ font-weight: 600;
17427
+ color: white;
17428
+ line-height: 2;
17216
17429
  }
17217
17430
 
17218
- .myio-power-limits-icon {
17431
+ .myio-modal-close {
17432
+ background: none;
17433
+ border: none;
17219
17434
  font-size: 24px;
17435
+ cursor: pointer;
17436
+ padding: 4px 12px;
17437
+ border-radius: 6px;
17438
+ color: rgba(255, 255, 255, 0.8);
17439
+ transition: background-color 0.2s, color 0.2s;
17440
+ line-height: 1;
17220
17441
  }
17221
17442
 
17222
- .myio-power-limits-title {
17223
- font-size: 1.25rem;
17224
- font-weight: 600;
17225
- margin: 0;
17443
+ .myio-modal-close:hover {
17444
+ background-color: rgba(255, 255, 255, 0.2);
17445
+ color: white;
17226
17446
  }
17227
17447
 
17228
- .myio-power-limits-actions {
17448
+ /* Toolbar with Save/Reset buttons */
17449
+ .myio-power-limits-toolbar {
17450
+ display: flex;
17451
+ justify-content: flex-end;
17452
+ padding: 16px 24px;
17453
+ background: #f9fafb;
17454
+ border-top: 1px solid #e5e7eb;
17455
+ }
17456
+
17457
+ .myio-toolbar-actions {
17229
17458
  display: flex;
17230
17459
  align-items: center;
17231
- gap: 8px;
17460
+ gap: 12px;
17232
17461
  }
17233
17462
 
17234
17463
  .myio-btn {
@@ -17250,33 +17479,21 @@ var PowerLimitsModalView = class {
17250
17479
  }
17251
17480
 
17252
17481
  .myio-btn-primary {
17253
- background: white;
17254
- color: ${primaryColor};
17482
+ background: ${primaryColor};
17483
+ color: white;
17255
17484
  }
17256
17485
 
17257
17486
  .myio-btn-primary:hover:not(:disabled) {
17258
- background: #f3f4f6;
17487
+ background: ${this.lightenColor(primaryColor, -10)};
17259
17488
  }
17260
17489
 
17261
17490
  .myio-btn-secondary {
17262
- background: rgba(255, 255, 255, 0.2);
17263
- color: white;
17491
+ background: #e5e7eb;
17492
+ color: #374151;
17264
17493
  }
17265
17494
 
17266
17495
  .myio-btn-secondary:hover:not(:disabled) {
17267
- background: rgba(255, 255, 255, 0.3);
17268
- }
17269
-
17270
- .myio-btn-close {
17271
- background: transparent;
17272
- color: white;
17273
- font-size: 24px;
17274
- padding: 4px 8px;
17275
- line-height: 1;
17276
- }
17277
-
17278
- .myio-btn-close:hover {
17279
- background: rgba(255, 255, 255, 0.1);
17496
+ background: #d1d5db;
17280
17497
  }
17281
17498
 
17282
17499
  .myio-btn-spinner {
@@ -17294,7 +17511,7 @@ var PowerLimitsModalView = class {
17294
17511
 
17295
17512
  .myio-power-limits-selectors {
17296
17513
  display: grid;
17297
- grid-template-columns: 1fr 1fr;
17514
+ grid-template-columns: 1fr 1fr 1fr;
17298
17515
  gap: 16px;
17299
17516
  padding: 20px 24px;
17300
17517
  background: #f9fafb;
@@ -17329,6 +17546,15 @@ var PowerLimitsModalView = class {
17329
17546
  box-shadow: 0 0 0 3px ${this.hexToRgba(primaryColor, 0.1)};
17330
17547
  }
17331
17548
 
17549
+ .myio-fixed-value {
17550
+ padding: 10px 12px;
17551
+ border: 1px solid #e5e7eb;
17552
+ border-radius: 6px;
17553
+ font-size: 14px;
17554
+ background: #f9fafb;
17555
+ color: #6b7280;
17556
+ }
17557
+
17332
17558
  .myio-power-limits-grid {
17333
17559
  display: grid;
17334
17560
  grid-template-columns: repeat(2, 1fr);
@@ -17357,6 +17583,11 @@ var PowerLimitsModalView = class {
17357
17583
  margin-bottom: 12px;
17358
17584
  }
17359
17585
 
17586
+ .myio-status-icon {
17587
+ font-size: 18px;
17588
+ line-height: 1;
17589
+ }
17590
+
17360
17591
  .myio-status-indicator {
17361
17592
  width: 12px;
17362
17593
  height: 12px;
@@ -17547,6 +17778,8 @@ var PowerLimitsPersister = class {
17547
17778
  const defaultFormData = {
17548
17779
  deviceType,
17549
17780
  telemetryType,
17781
+ domain: "energy",
17782
+ // Default to energy, will be overwritten by caller if needed
17550
17783
  standby: { baseValue: null, topValue: null },
17551
17784
  normal: { baseValue: null, topValue: null },
17552
17785
  alert: { baseValue: null, topValue: null },
@@ -17716,10 +17949,12 @@ async function openPowerLimitsSetupModal(params) {
17716
17949
  const persister = new PowerLimitsPersister(params.token, params.tbBaseUrl);
17717
17950
  let currentDeviceType = params.deviceType || "ELEVADOR";
17718
17951
  let currentTelemetryType = params.telemetryType || "consumption";
17952
+ let currentDomain = params.domain || "energy";
17719
17953
  let existingLimits = params.existingMapPower || null;
17720
17954
  const view = new PowerLimitsModalView({
17721
17955
  deviceType: currentDeviceType,
17722
17956
  telemetryType: currentTelemetryType,
17957
+ domain: currentDomain,
17723
17958
  styles: params.styles,
17724
17959
  locale: params.locale,
17725
17960
  onDeviceTypeChange: async (deviceType) => {
@@ -17730,6 +17965,9 @@ async function openPowerLimitsSetupModal(params) {
17730
17965
  currentTelemetryType = telemetryType;
17731
17966
  await loadFormData();
17732
17967
  },
17968
+ onDomainChange: (domain) => {
17969
+ currentDomain = domain;
17970
+ },
17733
17971
  onSave: async () => {
17734
17972
  const formData = view.getFormData();
17735
17973
  const updatedLimits = persister.mergeFormDataIntoLimits(existingLimits, formData);
@@ -17755,6 +17993,7 @@ async function openPowerLimitsSetupModal(params) {
17755
17993
  existingLimits = await persister.loadCustomerPowerLimits(params.customerId);
17756
17994
  }
17757
17995
  const formData = persister.extractFormData(existingLimits, currentDeviceType, currentTelemetryType);
17996
+ formData.domain = currentDomain;
17758
17997
  view.setFormData(formData);
17759
17998
  } catch (error) {
17760
17999
  console.error("[PowerLimitsSetupModal] Error loading form data:", error);