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.js CHANGED
@@ -5475,6 +5475,16 @@ function formatValueByDomain(value, domain) {
5475
5475
  }
5476
5476
  return formatEnergy(value);
5477
5477
  }
5478
+ function formatRelativeTime2(timestamp) {
5479
+ if (!timestamp || isNaN(timestamp)) return "\u2014";
5480
+ const date = new Date(timestamp);
5481
+ const hours = String(date.getHours()).padStart(2, "0");
5482
+ const minutes = String(date.getMinutes()).padStart(2, "0");
5483
+ const day = String(date.getDate()).padStart(2, "0");
5484
+ const month = String(date.getMonth() + 1).padStart(2, "0");
5485
+ const year = date.getFullYear();
5486
+ return `${hours}:${minutes} ${day}/${month}/${year}`;
5487
+ }
5478
5488
  function calculateConsumptionPercentage(target, consumption) {
5479
5489
  const numericTarget = Number(target);
5480
5490
  const numericConsumption = Number(consumption);
@@ -5727,6 +5737,8 @@ function buildDOM(state) {
5727
5737
  powerLabel.className = "label";
5728
5738
  if (entityObject.domain === "water") {
5729
5739
  powerLabel.textContent = "Leitura";
5740
+ } else if (entityObject.domain === "temperature") {
5741
+ powerLabel.textContent = "\xDAlt. Telemetria";
5730
5742
  } else {
5731
5743
  powerLabel.textContent = i18n.instantaneous_power || "Pot\xEAncia";
5732
5744
  }
@@ -5980,14 +5992,24 @@ function paint(root, state) {
5980
5992
  effContainer.style.display = "none";
5981
5993
  }
5982
5994
  const opTimeVal = root.querySelector(".myio-ho-card__footer .metric:nth-child(1) .val");
5995
+ const opTimeLabel = root.querySelector(".myio-ho-card__footer .metric:nth-child(1) .label");
5983
5996
  if (opTimeVal) {
5984
- opTimeVal.textContent = entityObject.operationHours ?? "-";
5997
+ if (entityObject.domain === "temperature") {
5998
+ if (opTimeLabel) opTimeLabel.textContent = "Temp. Atual";
5999
+ const currentTemp = entityObject.currentTemperature ?? entityObject.temperature ?? entityObject.val ?? null;
6000
+ opTimeVal.textContent = currentTemp !== null ? `${Number(currentTemp).toFixed(1)}\xB0C` : "-";
6001
+ } else {
6002
+ if (opTimeLabel) opTimeLabel.textContent = i18n.operation_time;
6003
+ opTimeVal.textContent = entityObject.operationHours ?? "-";
6004
+ }
5985
6005
  }
5986
6006
  const powerVal = root.querySelector(".myio-ho-card__footer .metric:nth-child(2) .val");
5987
6007
  if (powerVal) {
5988
6008
  if (entityObject.domain === "water") {
5989
6009
  const pulses = entityObject.pulses ?? 0;
5990
6010
  powerVal.textContent = `${pulses} L`;
6011
+ } else if (entityObject.domain === "temperature") {
6012
+ powerVal.textContent = entityObject.lastActivityTime ? formatRelativeTime2(entityObject.lastActivityTime) : "-";
5991
6013
  } else {
5992
6014
  const instantPower = entityObject.instantaneousPower ?? entityObject.consumption_power ?? null;
5993
6015
  const powerFormatted = formatPower(instantPower);
@@ -16640,35 +16662,72 @@ function validateOptions2(options) {
16640
16662
  }
16641
16663
 
16642
16664
  // src/components/premium-modals/power-limits/types.ts
16665
+ var DOMAINS = [
16666
+ { value: "energy", label: "Energia", icon: "\u26A1" },
16667
+ { value: "water", label: "\xC1gua", icon: "\u{1F4A7}" },
16668
+ { value: "temperature", label: "Temperatura", icon: "\u{1F321}\uFE0F" }
16669
+ ];
16643
16670
  var DEVICE_TYPES = [
16644
- { value: "ELEVADOR", label: "Elevator" },
16645
- { value: "ESCADA_ROLANTE", label: "Escalator" },
16671
+ { value: "ELEVADOR", label: "Elevador" },
16672
+ { value: "ESCADA_ROLANTE", label: "Escada Rolante" },
16646
16673
  { value: "MOTOR", label: "Motor" },
16647
- { value: "BOMBA", label: "Pump" },
16674
+ { value: "BOMBA", label: "Bomba" },
16648
16675
  { value: "CHILLER", label: "Chiller" },
16649
- { value: "AR_CONDICIONADO", label: "Air Conditioner" },
16676
+ { value: "AR_CONDICIONADO", label: "Ar Condicionado" },
16650
16677
  { value: "HVAC", label: "HVAC" },
16651
16678
  { value: "FANCOIL", label: "Fancoil" },
16652
- { value: "3F_MEDIDOR", label: "Three-phase Meter" }
16679
+ { value: "3F_MEDIDOR", label: "Medidor Trif\xE1sico" }
16653
16680
  ];
16654
16681
  var TELEMETRY_TYPES2 = [
16655
- { value: "consumption", label: "Consumption (kW)", unit: "kW" },
16656
- { value: "voltage_a", label: "Voltage A (V)", unit: "V" },
16657
- { value: "voltage_b", label: "Voltage B (V)", unit: "V" },
16658
- { value: "voltage_c", label: "Voltage C (V)", unit: "V" },
16659
- { value: "current_a", label: "Current A (A)", unit: "A" },
16660
- { value: "current_b", label: "Current B (A)", unit: "A" },
16661
- { value: "current_c", label: "Current C (A)", unit: "A" },
16662
- { value: "total_current", label: "Total Current (A)", unit: "A" },
16663
- { value: "fp_a", label: "Power Factor A", unit: "" },
16664
- { value: "fp_b", label: "Power Factor B", unit: "" },
16665
- { value: "fp_c", label: "Power Factor C", unit: "" }
16682
+ { value: "consumption", label: "Pot\xEAncia (kW)", unit: "kW" },
16683
+ { value: "voltage_a", label: "Tens\xE3o A (V)", unit: "V" },
16684
+ { value: "voltage_b", label: "Tens\xE3o B (V)", unit: "V" },
16685
+ { value: "voltage_c", label: "Tens\xE3o C (V)", unit: "V" },
16686
+ { value: "current_a", label: "Corrente A (A)", unit: "A" },
16687
+ { value: "current_b", label: "Corrente B (A)", unit: "A" },
16688
+ { value: "current_c", label: "Corrente C (A)", unit: "A" },
16689
+ { value: "total_current", label: "Corrente Total (A)", unit: "A" },
16690
+ { value: "fp_a", label: "Fator de Pot\xEAncia A", unit: "" },
16691
+ { value: "fp_b", label: "Fator de Pot\xEAncia B", unit: "" },
16692
+ { value: "fp_c", label: "Fator de Pot\xEAncia C", unit: "" }
16666
16693
  ];
16694
+ var STATUS_ICONS = {
16695
+ energy: {
16696
+ standBy: "\u{1F50C}",
16697
+ // STANDBY
16698
+ normal: "\u26A1",
16699
+ // POWER_ON
16700
+ alert: "\u26A0\uFE0F",
16701
+ // WARNING
16702
+ failure: "\u{1F6A8}"
16703
+ // FAILURE
16704
+ },
16705
+ water: {
16706
+ standBy: "\u{1F6B0}",
16707
+ // STANDBY
16708
+ normal: "\u{1F4A7}",
16709
+ // POWER_ON
16710
+ alert: "\u26A0\uFE0F",
16711
+ // WARNING
16712
+ failure: "\u{1F6A8}"
16713
+ // FAILURE
16714
+ },
16715
+ temperature: {
16716
+ standBy: "\u{1F321}\uFE0F",
16717
+ // STANDBY
16718
+ normal: "\u{1F321}\uFE0F",
16719
+ // POWER_ON
16720
+ alert: "\u26A0\uFE0F",
16721
+ // WARNING
16722
+ failure: "\u{1F6A8}"
16723
+ // FAILURE
16724
+ }
16725
+ };
16667
16726
  var STATUS_CONFIG = {
16668
16727
  standBy: { label: "StandBy", color: "#22c55e", bgColor: "rgba(34, 197, 94, 0.1)" },
16669
16728
  normal: { label: "Normal", color: "#3b82f6", bgColor: "rgba(59, 130, 246, 0.1)" },
16670
- alert: { label: "Alert", color: "#f59e0b", bgColor: "rgba(245, 158, 11, 0.1)" },
16671
- failure: { label: "Failure", color: "#ef4444", bgColor: "rgba(239, 68, 68, 0.1)" }
16729
+ alert: { label: "Alerta", color: "#f59e0b", bgColor: "rgba(245, 158, 11, 0.1)" },
16730
+ failure: { label: "Falha", color: "#ef4444", bgColor: "rgba(239, 68, 68, 0.1)" }
16672
16731
  };
16673
16732
 
16674
16733
  // src/components/premium-modals/power-limits/PowerLimitsModalView.ts
@@ -16684,12 +16743,43 @@ var PowerLimitsModalView = class {
16684
16743
  this.formData = {
16685
16744
  deviceType: config.deviceType,
16686
16745
  telemetryType: config.telemetryType,
16746
+ domain: config.domain,
16687
16747
  standby: { baseValue: null, topValue: null },
16688
16748
  normal: { baseValue: null, topValue: null },
16689
16749
  alert: { baseValue: null, topValue: null },
16690
16750
  failure: { baseValue: null, topValue: null }
16691
16751
  };
16692
16752
  }
16753
+ // Format number with thousand separator (.) and up to 2 decimal places
16754
+ formatNumberForDisplay(value) {
16755
+ if (value === null || value === void 0) return "";
16756
+ const parts = value.toFixed(2).split(".");
16757
+ parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ".");
16758
+ return parts.join(",");
16759
+ }
16760
+ // Parse formatted string back to number
16761
+ parseFormattedNumber(value) {
16762
+ if (!value || value.trim() === "") return null;
16763
+ const normalized = value.replace(/\./g, "").replace(",", ".");
16764
+ const num = parseFloat(normalized);
16765
+ return isNaN(num) ? null : num;
16766
+ }
16767
+ // Handle input formatting on blur
16768
+ formatInputValue(input) {
16769
+ const rawValue = input.value;
16770
+ const parsed = this.parseFormattedNumber(rawValue);
16771
+ if (parsed !== null) {
16772
+ input.value = this.formatNumberForDisplay(parsed);
16773
+ }
16774
+ }
16775
+ // Handle input on focus - show raw value for editing
16776
+ unformatInputValue(input) {
16777
+ const formatted = input.value;
16778
+ const parsed = this.parseFormattedNumber(formatted);
16779
+ if (parsed !== null) {
16780
+ input.value = parsed.toString().replace(".", ",");
16781
+ }
16782
+ }
16693
16783
  render(targetContainer) {
16694
16784
  this.overlayEl = document.createElement("div");
16695
16785
  this.overlayEl.className = "myio-power-limits-overlay";
@@ -16699,6 +16789,7 @@ var PowerLimitsModalView = class {
16699
16789
  ${this.renderHeader()}
16700
16790
  ${this.renderSelectors()}
16701
16791
  ${this.renderStatusCards()}
16792
+ ${this.renderToolbar()}
16702
16793
  ${this.renderLoadingState()}
16703
16794
  ${this.renderErrorState()}
16704
16795
  ${this.renderSuccessState()}
@@ -16715,80 +16806,107 @@ var PowerLimitsModalView = class {
16715
16806
  }
16716
16807
  renderHeader() {
16717
16808
  return `
16718
- <div class="myio-power-limits-header">
16719
- <div class="myio-power-limits-title-section">
16720
- <span class="myio-power-limits-icon">&#x2699;</span>
16721
- <h2 class="myio-power-limits-title">Power Limits Setup</h2>
16722
- </div>
16723
- <div class="myio-power-limits-actions">
16809
+ <div class="myio-modal-header">
16810
+ <h2 class="myio-modal-title">\u2699\uFE0F Configura\xE7\xE3o de Limites</h2>
16811
+ <button class="myio-modal-close" id="plm-close-btn" type="button" aria-label="Fechar modal">\xD7</button>
16812
+ </div>
16813
+ `;
16814
+ }
16815
+ renderToolbar() {
16816
+ return `
16817
+ <div class="myio-power-limits-toolbar">
16818
+ <div class="myio-toolbar-actions">
16819
+ <button class="myio-btn myio-btn-secondary" id="plm-reset-btn" type="button">Limpar</button>
16724
16820
  <button class="myio-btn myio-btn-primary" id="plm-save-btn" type="button">
16725
- <span class="myio-btn-text">Save</span>
16821
+ <span class="myio-btn-text">Salvar</span>
16726
16822
  <span class="myio-btn-spinner" style="display: none;"></span>
16727
16823
  </button>
16728
- <button class="myio-btn myio-btn-secondary" id="plm-reset-btn" type="button">Reset</button>
16729
- <button class="myio-btn myio-btn-close" id="plm-close-btn" type="button" aria-label="Close">&times;</button>
16730
16824
  </div>
16731
16825
  </div>
16732
16826
  `;
16733
16827
  }
16734
16828
  renderSelectors() {
16735
- const deviceOptions = DEVICE_TYPES.map(
16736
- (dt) => `<option value="${dt.value}" ${dt.value === this.config.deviceType ? "selected" : ""}>${dt.label}</option>`
16737
- ).join("");
16738
- const telemetryOptions = TELEMETRY_TYPES2.map(
16739
- (tt) => `<option value="${tt.value}" ${tt.value === this.config.telemetryType ? "selected" : ""}>${tt.label}</option>`
16829
+ const domain = this.formData.domain || "energy";
16830
+ const domainOptions = DOMAINS.map(
16831
+ (d) => `<option value="${d.value}" ${d.value === domain ? "selected" : ""}>${d.icon} ${d.label}</option>`
16740
16832
  ).join("");
16833
+ let deviceTypeContent;
16834
+ let telemetryLabel;
16835
+ switch (domain) {
16836
+ case "temperature":
16837
+ deviceTypeContent = `<div class="myio-fixed-value">Sensor de Temperatura</div>`;
16838
+ telemetryLabel = "Temperatura em Celsius";
16839
+ break;
16840
+ case "water":
16841
+ deviceTypeContent = `<div class="myio-fixed-value">Hidr\xF4metro</div>`;
16842
+ telemetryLabel = "Litros";
16843
+ break;
16844
+ case "energy":
16845
+ default:
16846
+ deviceTypeContent = `<select id="plm-device-type" class="myio-select">
16847
+ ${DEVICE_TYPES.map(
16848
+ (dt) => `<option value="${dt.value}" ${dt.value === this.formData.deviceType ? "selected" : ""}>${dt.label}</option>`
16849
+ ).join("")}
16850
+ </select>`;
16851
+ telemetryLabel = "Pot\xEAncia (kW)";
16852
+ break;
16853
+ }
16741
16854
  return `
16742
16855
  <div class="myio-power-limits-selectors">
16743
16856
  <div class="myio-form-group">
16744
- <label for="plm-device-type">Device Type</label>
16745
- <select id="plm-device-type" class="myio-select">
16746
- ${deviceOptions}
16857
+ <label for="plm-domain">Dom\xEDnio</label>
16858
+ <select id="plm-domain" class="myio-select">
16859
+ ${domainOptions}
16747
16860
  </select>
16748
16861
  </div>
16749
16862
  <div class="myio-form-group">
16750
- <label for="plm-telemetry-type">Telemetry Type</label>
16751
- <select id="plm-telemetry-type" class="myio-select">
16752
- ${telemetryOptions}
16753
- </select>
16863
+ <label>Tipo de Dispositivo</label>
16864
+ ${deviceTypeContent}
16865
+ </div>
16866
+ <div class="myio-form-group">
16867
+ <label>Tipo de Telemetria</label>
16868
+ <div class="myio-fixed-value">${telemetryLabel}</div>
16754
16869
  </div>
16755
16870
  </div>
16756
16871
  `;
16757
16872
  }
16758
16873
  renderStatusCards() {
16759
16874
  const statuses = ["standby", "normal", "alert", "failure"];
16875
+ const domain = this.formData.domain || "energy";
16876
+ const domainIcons = STATUS_ICONS[domain];
16760
16877
  const cards = statuses.map((status) => {
16761
- const config = STATUS_CONFIG[status === "standby" ? "standBy" : status];
16878
+ const statusKey = status === "standby" ? "standBy" : status;
16879
+ const config = STATUS_CONFIG[statusKey];
16762
16880
  const formValues = this.formData[status];
16881
+ const icon = domainIcons[statusKey];
16763
16882
  return `
16764
16883
  <div class="myio-power-limits-card-item myio-status-${status}" style="--status-color: ${config.color}; --status-bg: ${config.bgColor};">
16765
16884
  <div class="myio-card-header">
16885
+ <span class="myio-status-icon">${icon}</span>
16766
16886
  <span class="myio-status-indicator"></span>
16767
16887
  <span class="myio-status-label">${config.label}</span>
16768
16888
  </div>
16769
16889
  <div class="myio-card-inputs">
16770
16890
  <div class="myio-input-group">
16771
- <label for="plm-${status}-base">Base Value</label>
16891
+ <label for="plm-${status}-base">Limite Inferior</label>
16772
16892
  <input
16773
- type="number"
16893
+ type="text"
16774
16894
  id="plm-${status}-base"
16775
- class="myio-input"
16776
- min="0"
16777
- step="0.01"
16778
- value="${formValues.baseValue ?? ""}"
16779
- placeholder="0"
16895
+ class="myio-input myio-formatted-number"
16896
+ inputmode="decimal"
16897
+ value="${this.formatNumberForDisplay(formValues.baseValue)}"
16898
+ placeholder="0,00"
16780
16899
  >
16781
16900
  </div>
16782
16901
  <div class="myio-input-group">
16783
- <label for="plm-${status}-top">Top Value</label>
16902
+ <label for="plm-${status}-top">Limite Superior</label>
16784
16903
  <input
16785
- type="number"
16904
+ type="text"
16786
16905
  id="plm-${status}-top"
16787
- class="myio-input"
16788
- min="0"
16789
- step="0.01"
16790
- value="${formValues.topValue ?? ""}"
16791
- placeholder="0"
16906
+ class="myio-input myio-formatted-number"
16907
+ inputmode="decimal"
16908
+ value="${this.formatNumberForDisplay(formValues.topValue)}"
16909
+ placeholder="0,00"
16792
16910
  >
16793
16911
  </div>
16794
16912
  </div>
@@ -16805,7 +16923,7 @@ var PowerLimitsModalView = class {
16805
16923
  return `
16806
16924
  <div class="myio-power-limits-loading" id="plm-loading" style="display: none;">
16807
16925
  <div class="myio-spinner"></div>
16808
- <span>Loading configuration...</span>
16926
+ <span>Carregando configura\xE7\xE3o...</span>
16809
16927
  </div>
16810
16928
  `;
16811
16929
  }
@@ -16821,7 +16939,7 @@ var PowerLimitsModalView = class {
16821
16939
  return `
16822
16940
  <div class="myio-power-limits-success" id="plm-success" style="display: none;">
16823
16941
  <span class="myio-success-icon">&#x2713;</span>
16824
- <span class="myio-success-message">Configuration saved successfully!</span>
16942
+ <span class="myio-success-message">Configura\xE7\xE3o salva com sucesso!</span>
16825
16943
  </div>
16826
16944
  `;
16827
16945
  }
@@ -16839,31 +16957,121 @@ var PowerLimitsModalView = class {
16839
16957
  saveBtn?.addEventListener("click", () => this.handleSave());
16840
16958
  const resetBtn = this.overlayEl.querySelector("#plm-reset-btn");
16841
16959
  resetBtn?.addEventListener("click", () => this.handleReset());
16842
- const deviceSelect = this.overlayEl.querySelector("#plm-device-type");
16843
- deviceSelect?.addEventListener("change", (e) => {
16844
- const value = e.target.value;
16845
- this.formData.deviceType = value;
16846
- this.config.onDeviceTypeChange(value);
16847
- });
16848
- const telemetrySelect = this.overlayEl.querySelector("#plm-telemetry-type");
16849
- telemetrySelect?.addEventListener("change", (e) => {
16960
+ const domainSelect = this.overlayEl.querySelector("#plm-domain");
16961
+ domainSelect?.addEventListener("change", (e) => {
16850
16962
  const value = e.target.value;
16851
- this.formData.telemetryType = value;
16852
- this.config.onTelemetryTypeChange(value);
16963
+ this.formData.domain = value;
16964
+ switch (value) {
16965
+ case "temperature":
16966
+ this.formData.deviceType = "SENSOR_TEMPERATURA";
16967
+ this.formData.telemetryType = "temperature";
16968
+ break;
16969
+ case "water":
16970
+ this.formData.deviceType = "HIDROMETRO";
16971
+ this.formData.telemetryType = "liters";
16972
+ break;
16973
+ case "energy":
16974
+ default:
16975
+ this.formData.telemetryType = "consumption";
16976
+ break;
16977
+ }
16978
+ this.config.onDomainChange(value);
16979
+ this.updateSelectorsUI();
16980
+ this.updateStatusIcons();
16853
16981
  });
16982
+ this.setupDeviceTypeListener();
16854
16983
  const statuses = ["standby", "normal", "alert", "failure"];
16855
16984
  statuses.forEach((status) => {
16856
16985
  const baseInput = this.overlayEl?.querySelector(`#plm-${status}-base`);
16857
16986
  const topInput = this.overlayEl?.querySelector(`#plm-${status}-top`);
16858
- baseInput?.addEventListener("input", (e) => {
16987
+ if (baseInput) {
16988
+ baseInput.addEventListener("focus", () => this.unformatInputValue(baseInput));
16989
+ baseInput.addEventListener("blur", () => {
16990
+ this.formData[status].baseValue = this.parseFormattedNumber(baseInput.value);
16991
+ this.formatInputValue(baseInput);
16992
+ });
16993
+ baseInput.addEventListener("keydown", (e) => this.handleNumberKeydown(e));
16994
+ }
16995
+ if (topInput) {
16996
+ topInput.addEventListener("focus", () => this.unformatInputValue(topInput));
16997
+ topInput.addEventListener("blur", () => {
16998
+ this.formData[status].topValue = this.parseFormattedNumber(topInput.value);
16999
+ this.formatInputValue(topInput);
17000
+ });
17001
+ topInput.addEventListener("keydown", (e) => this.handleNumberKeydown(e));
17002
+ }
17003
+ });
17004
+ }
17005
+ // Handle keyboard input to allow only valid number characters
17006
+ handleNumberKeydown(e) {
17007
+ const allowedKeys = ["Backspace", "Delete", "ArrowLeft", "ArrowRight", "Tab", "Home", "End"];
17008
+ const isDigit = /^\d$/.test(e.key);
17009
+ const isComma = e.key === ",";
17010
+ const isAllowedKey = allowedKeys.includes(e.key);
17011
+ const hasCtrl = e.ctrlKey || e.metaKey;
17012
+ if (!isDigit && !isComma && !isAllowedKey && !hasCtrl) {
17013
+ e.preventDefault();
17014
+ }
17015
+ if (isComma) {
17016
+ const input = e.target;
17017
+ if (input.value.includes(",")) {
17018
+ e.preventDefault();
17019
+ }
17020
+ }
17021
+ }
17022
+ // Update status icons when domain changes
17023
+ updateStatusIcons() {
17024
+ const domain = this.formData.domain || "energy";
17025
+ const domainIcons = STATUS_ICONS[domain];
17026
+ const statuses = ["standby", "normal", "alert", "failure"];
17027
+ statuses.forEach((status) => {
17028
+ const statusKey = status === "standby" ? "standBy" : status;
17029
+ const iconEl = this.overlayEl?.querySelector(`.myio-status-${status} .myio-status-icon`);
17030
+ if (iconEl) {
17031
+ iconEl.textContent = domainIcons[statusKey];
17032
+ }
17033
+ });
17034
+ }
17035
+ // Update selectors UI when domain changes
17036
+ updateSelectorsUI() {
17037
+ const selectorsContainer = this.overlayEl?.querySelector(".myio-power-limits-selectors");
17038
+ if (selectorsContainer) {
17039
+ selectorsContainer.outerHTML = this.renderSelectors();
17040
+ const domainSelect = this.overlayEl?.querySelector("#plm-domain");
17041
+ domainSelect?.addEventListener("change", (e) => {
16859
17042
  const value = e.target.value;
16860
- this.formData[status].baseValue = value ? parseFloat(value) : null;
17043
+ this.formData.domain = value;
17044
+ switch (value) {
17045
+ case "temperature":
17046
+ this.formData.deviceType = "SENSOR_TEMPERATURA";
17047
+ this.formData.telemetryType = "temperature";
17048
+ break;
17049
+ case "water":
17050
+ this.formData.deviceType = "HIDROMETRO";
17051
+ this.formData.telemetryType = "liters";
17052
+ break;
17053
+ case "energy":
17054
+ default:
17055
+ this.formData.telemetryType = "consumption";
17056
+ break;
17057
+ }
17058
+ this.config.onDomainChange(value);
17059
+ this.updateSelectorsUI();
17060
+ this.updateStatusIcons();
16861
17061
  });
16862
- topInput?.addEventListener("input", (e) => {
17062
+ this.setupDeviceTypeListener();
17063
+ }
17064
+ }
17065
+ // Setup device type listener (only for energy/water domains)
17066
+ setupDeviceTypeListener() {
17067
+ const deviceSelect = this.overlayEl?.querySelector("#plm-device-type");
17068
+ if (deviceSelect) {
17069
+ deviceSelect.addEventListener("change", (e) => {
16863
17070
  const value = e.target.value;
16864
- this.formData[status].topValue = value ? parseFloat(value) : null;
17071
+ this.formData.deviceType = value;
17072
+ this.config.onDeviceTypeChange(value);
16865
17073
  });
16866
- });
17074
+ }
16867
17075
  }
16868
17076
  handleKeyDown = (e) => {
16869
17077
  if (e.key === "Escape") {
@@ -16886,7 +17094,7 @@ var PowerLimitsModalView = class {
16886
17094
  this.showSuccess();
16887
17095
  setTimeout(() => this.hideSuccess(), 3e3);
16888
17096
  } catch (error) {
16889
- this.showError(error.message || "Failed to save configuration");
17097
+ this.showError(error.message || "Falha ao salvar configura\xE7\xE3o");
16890
17098
  } finally {
16891
17099
  this.isSaving = false;
16892
17100
  this.showSaveLoading(false);
@@ -16910,13 +17118,13 @@ var PowerLimitsModalView = class {
16910
17118
  const base = this.formData[status].baseValue;
16911
17119
  const top = this.formData[status].topValue;
16912
17120
  if (base !== null && base < 0) {
16913
- return `${STATUS_CONFIG[status === "standby" ? "standBy" : status].label}: Base value cannot be negative`;
17121
+ return `${STATUS_CONFIG[status === "standby" ? "standBy" : status].label}: Limite inferior n\xE3o pode ser negativo`;
16914
17122
  }
16915
17123
  if (top !== null && top < 0) {
16916
- return `${STATUS_CONFIG[status === "standby" ? "standBy" : status].label}: Top value cannot be negative`;
17124
+ return `${STATUS_CONFIG[status === "standby" ? "standBy" : status].label}: Limite superior n\xE3o pode ser negativo`;
16917
17125
  }
16918
17126
  if (base !== null && top !== null && base > top) {
16919
- return `${STATUS_CONFIG[status === "standby" ? "standBy" : status].label}: Base value should not exceed top value`;
17127
+ return `${STATUS_CONFIG[status === "standby" ? "standBy" : status].label}: Limite inferior n\xE3o pode ser maior que o limite superior`;
16920
17128
  }
16921
17129
  }
16922
17130
  return null;
@@ -16985,11 +17193,13 @@ var PowerLimitsModalView = class {
16985
17193
  setFormData(data) {
16986
17194
  if (data.deviceType) this.formData.deviceType = data.deviceType;
16987
17195
  if (data.telemetryType) this.formData.telemetryType = data.telemetryType;
17196
+ if (data.domain) this.formData.domain = data.domain;
16988
17197
  if (data.standby) this.formData.standby = { ...data.standby };
16989
17198
  if (data.normal) this.formData.normal = { ...data.normal };
16990
17199
  if (data.alert) this.formData.alert = { ...data.alert };
16991
17200
  if (data.failure) this.formData.failure = { ...data.failure };
16992
17201
  this.updateInputValues();
17202
+ this.updateStatusIcons();
16993
17203
  }
16994
17204
  updateInputValues() {
16995
17205
  const statuses = ["standby", "normal", "alert", "failure"];
@@ -16997,16 +17207,16 @@ var PowerLimitsModalView = class {
16997
17207
  const baseInput = this.overlayEl?.querySelector(`#plm-${status}-base`);
16998
17208
  const topInput = this.overlayEl?.querySelector(`#plm-${status}-top`);
16999
17209
  if (baseInput) {
17000
- baseInput.value = this.formData[status].baseValue?.toString() ?? "";
17210
+ baseInput.value = this.formatNumberForDisplay(this.formData[status].baseValue);
17001
17211
  }
17002
17212
  if (topInput) {
17003
- topInput.value = this.formData[status].topValue?.toString() ?? "";
17213
+ topInput.value = this.formatNumberForDisplay(this.formData[status].topValue);
17004
17214
  }
17005
17215
  });
17216
+ const domainSelect = this.overlayEl?.querySelector("#plm-domain");
17006
17217
  const deviceSelect = this.overlayEl?.querySelector("#plm-device-type");
17007
- const telemetrySelect = this.overlayEl?.querySelector("#plm-telemetry-type");
17218
+ if (domainSelect) domainSelect.value = this.formData.domain;
17008
17219
  if (deviceSelect) deviceSelect.value = this.formData.deviceType;
17009
- if (telemetrySelect) telemetrySelect.value = this.formData.telemetryType;
17010
17220
  }
17011
17221
  getStyles() {
17012
17222
  const styles = this.config.styles || {};
@@ -17030,7 +17240,7 @@ var PowerLimitsModalView = class {
17030
17240
  opacity: 0;
17031
17241
  visibility: hidden;
17032
17242
  transition: all 0.3s ease;
17033
- font-family: ${styles.fontFamily || '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'};
17243
+ font-family: ${styles.fontFamily || "'Roboto', Arial, sans-serif"};
17034
17244
  }
17035
17245
 
17036
17246
  .myio-power-limits-overlay.active {
@@ -17040,9 +17250,9 @@ var PowerLimitsModalView = class {
17040
17250
 
17041
17251
  .myio-power-limits-card {
17042
17252
  background: ${styles.backgroundColor || "#ffffff"};
17043
- border-radius: ${styles.borderRadius || "12px"};
17253
+ border-radius: ${styles.borderRadius || "10px"};
17044
17254
  width: 90%;
17045
- max-width: 875px;
17255
+ max-width: 1104px;
17046
17256
  max-height: 90vh;
17047
17257
  overflow-y: auto;
17048
17258
  transform: scale(0.9);
@@ -17054,36 +17264,55 @@ var PowerLimitsModalView = class {
17054
17264
  transform: scale(1);
17055
17265
  }
17056
17266
 
17057
- .myio-power-limits-header {
17267
+ /* Header - ModalPremiumShell pattern */
17268
+ .myio-modal-header {
17058
17269
  display: flex;
17059
17270
  align-items: center;
17060
17271
  justify-content: space-between;
17061
- padding: 20px 24px;
17062
- background: linear-gradient(135deg, ${primaryColor}, ${this.lightenColor(primaryColor, 20)});
17063
- color: white;
17064
- border-radius: 12px 12px 0 0;
17272
+ padding: 4px 8px;
17273
+ background: ${primaryColor};
17274
+ border-radius: 10px 10px 0 0;
17275
+ min-height: 20px;
17065
17276
  }
17066
17277
 
17067
- .myio-power-limits-title-section {
17068
- display: flex;
17069
- align-items: center;
17070
- gap: 12px;
17278
+ .myio-modal-title {
17279
+ margin: 6px;
17280
+ font-size: 18px;
17281
+ font-weight: 600;
17282
+ color: white;
17283
+ line-height: 2;
17071
17284
  }
17072
17285
 
17073
- .myio-power-limits-icon {
17286
+ .myio-modal-close {
17287
+ background: none;
17288
+ border: none;
17074
17289
  font-size: 24px;
17290
+ cursor: pointer;
17291
+ padding: 4px 12px;
17292
+ border-radius: 6px;
17293
+ color: rgba(255, 255, 255, 0.8);
17294
+ transition: background-color 0.2s, color 0.2s;
17295
+ line-height: 1;
17075
17296
  }
17076
17297
 
17077
- .myio-power-limits-title {
17078
- font-size: 1.25rem;
17079
- font-weight: 600;
17080
- margin: 0;
17298
+ .myio-modal-close:hover {
17299
+ background-color: rgba(255, 255, 255, 0.2);
17300
+ color: white;
17081
17301
  }
17082
17302
 
17083
- .myio-power-limits-actions {
17303
+ /* Toolbar with Save/Reset buttons */
17304
+ .myio-power-limits-toolbar {
17305
+ display: flex;
17306
+ justify-content: flex-end;
17307
+ padding: 16px 24px;
17308
+ background: #f9fafb;
17309
+ border-top: 1px solid #e5e7eb;
17310
+ }
17311
+
17312
+ .myio-toolbar-actions {
17084
17313
  display: flex;
17085
17314
  align-items: center;
17086
- gap: 8px;
17315
+ gap: 12px;
17087
17316
  }
17088
17317
 
17089
17318
  .myio-btn {
@@ -17105,33 +17334,21 @@ var PowerLimitsModalView = class {
17105
17334
  }
17106
17335
 
17107
17336
  .myio-btn-primary {
17108
- background: white;
17109
- color: ${primaryColor};
17337
+ background: ${primaryColor};
17338
+ color: white;
17110
17339
  }
17111
17340
 
17112
17341
  .myio-btn-primary:hover:not(:disabled) {
17113
- background: #f3f4f6;
17342
+ background: ${this.lightenColor(primaryColor, -10)};
17114
17343
  }
17115
17344
 
17116
17345
  .myio-btn-secondary {
17117
- background: rgba(255, 255, 255, 0.2);
17118
- color: white;
17346
+ background: #e5e7eb;
17347
+ color: #374151;
17119
17348
  }
17120
17349
 
17121
17350
  .myio-btn-secondary:hover:not(:disabled) {
17122
- background: rgba(255, 255, 255, 0.3);
17123
- }
17124
-
17125
- .myio-btn-close {
17126
- background: transparent;
17127
- color: white;
17128
- font-size: 24px;
17129
- padding: 4px 8px;
17130
- line-height: 1;
17131
- }
17132
-
17133
- .myio-btn-close:hover {
17134
- background: rgba(255, 255, 255, 0.1);
17351
+ background: #d1d5db;
17135
17352
  }
17136
17353
 
17137
17354
  .myio-btn-spinner {
@@ -17149,7 +17366,7 @@ var PowerLimitsModalView = class {
17149
17366
 
17150
17367
  .myio-power-limits-selectors {
17151
17368
  display: grid;
17152
- grid-template-columns: 1fr 1fr;
17369
+ grid-template-columns: 1fr 1fr 1fr;
17153
17370
  gap: 16px;
17154
17371
  padding: 20px 24px;
17155
17372
  background: #f9fafb;
@@ -17184,6 +17401,15 @@ var PowerLimitsModalView = class {
17184
17401
  box-shadow: 0 0 0 3px ${this.hexToRgba(primaryColor, 0.1)};
17185
17402
  }
17186
17403
 
17404
+ .myio-fixed-value {
17405
+ padding: 10px 12px;
17406
+ border: 1px solid #e5e7eb;
17407
+ border-radius: 6px;
17408
+ font-size: 14px;
17409
+ background: #f9fafb;
17410
+ color: #6b7280;
17411
+ }
17412
+
17187
17413
  .myio-power-limits-grid {
17188
17414
  display: grid;
17189
17415
  grid-template-columns: repeat(2, 1fr);
@@ -17212,6 +17438,11 @@ var PowerLimitsModalView = class {
17212
17438
  margin-bottom: 12px;
17213
17439
  }
17214
17440
 
17441
+ .myio-status-icon {
17442
+ font-size: 18px;
17443
+ line-height: 1;
17444
+ }
17445
+
17215
17446
  .myio-status-indicator {
17216
17447
  width: 12px;
17217
17448
  height: 12px;
@@ -17402,6 +17633,8 @@ var PowerLimitsPersister = class {
17402
17633
  const defaultFormData = {
17403
17634
  deviceType,
17404
17635
  telemetryType,
17636
+ domain: "energy",
17637
+ // Default to energy, will be overwritten by caller if needed
17405
17638
  standby: { baseValue: null, topValue: null },
17406
17639
  normal: { baseValue: null, topValue: null },
17407
17640
  alert: { baseValue: null, topValue: null },
@@ -17571,10 +17804,12 @@ async function openPowerLimitsSetupModal(params) {
17571
17804
  const persister = new PowerLimitsPersister(params.token, params.tbBaseUrl);
17572
17805
  let currentDeviceType = params.deviceType || "ELEVADOR";
17573
17806
  let currentTelemetryType = params.telemetryType || "consumption";
17807
+ let currentDomain = params.domain || "energy";
17574
17808
  let existingLimits = params.existingMapPower || null;
17575
17809
  const view = new PowerLimitsModalView({
17576
17810
  deviceType: currentDeviceType,
17577
17811
  telemetryType: currentTelemetryType,
17812
+ domain: currentDomain,
17578
17813
  styles: params.styles,
17579
17814
  locale: params.locale,
17580
17815
  onDeviceTypeChange: async (deviceType) => {
@@ -17585,6 +17820,9 @@ async function openPowerLimitsSetupModal(params) {
17585
17820
  currentTelemetryType = telemetryType;
17586
17821
  await loadFormData();
17587
17822
  },
17823
+ onDomainChange: (domain) => {
17824
+ currentDomain = domain;
17825
+ },
17588
17826
  onSave: async () => {
17589
17827
  const formData = view.getFormData();
17590
17828
  const updatedLimits = persister.mergeFormDataIntoLimits(existingLimits, formData);
@@ -17610,6 +17848,7 @@ async function openPowerLimitsSetupModal(params) {
17610
17848
  existingLimits = await persister.loadCustomerPowerLimits(params.customerId);
17611
17849
  }
17612
17850
  const formData = persister.extractFormData(existingLimits, currentDeviceType, currentTelemetryType);
17851
+ formData.domain = currentDomain;
17613
17852
  view.setFormData(formData);
17614
17853
  } catch (error) {
17615
17854
  console.error("[PowerLimitsSetupModal] Error loading form data:", error);