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.
@@ -5466,6 +5466,16 @@
5466
5466
  }
5467
5467
  return formatEnergy(value);
5468
5468
  }
5469
+ function formatRelativeTime2(timestamp) {
5470
+ if (!timestamp || isNaN(timestamp)) return "\u2014";
5471
+ const date = new Date(timestamp);
5472
+ const hours = String(date.getHours()).padStart(2, "0");
5473
+ const minutes = String(date.getMinutes()).padStart(2, "0");
5474
+ const day = String(date.getDate()).padStart(2, "0");
5475
+ const month = String(date.getMonth() + 1).padStart(2, "0");
5476
+ const year = date.getFullYear();
5477
+ return `${hours}:${minutes} ${day}/${month}/${year}`;
5478
+ }
5469
5479
  function calculateConsumptionPercentage(target, consumption) {
5470
5480
  const numericTarget = Number(target);
5471
5481
  const numericConsumption = Number(consumption);
@@ -5718,6 +5728,8 @@
5718
5728
  powerLabel.className = "label";
5719
5729
  if (entityObject.domain === "water") {
5720
5730
  powerLabel.textContent = "Leitura";
5731
+ } else if (entityObject.domain === "temperature") {
5732
+ powerLabel.textContent = "\xDAlt. Telemetria";
5721
5733
  } else {
5722
5734
  powerLabel.textContent = i18n.instantaneous_power || "Pot\xEAncia";
5723
5735
  }
@@ -5971,14 +5983,24 @@
5971
5983
  effContainer.style.display = "none";
5972
5984
  }
5973
5985
  const opTimeVal = root.querySelector(".myio-ho-card__footer .metric:nth-child(1) .val");
5986
+ const opTimeLabel = root.querySelector(".myio-ho-card__footer .metric:nth-child(1) .label");
5974
5987
  if (opTimeVal) {
5975
- opTimeVal.textContent = entityObject.operationHours ?? "-";
5988
+ if (entityObject.domain === "temperature") {
5989
+ if (opTimeLabel) opTimeLabel.textContent = "Temp. Atual";
5990
+ const currentTemp = entityObject.currentTemperature ?? entityObject.temperature ?? entityObject.val ?? null;
5991
+ opTimeVal.textContent = currentTemp !== null ? `${Number(currentTemp).toFixed(1)}\xB0C` : "-";
5992
+ } else {
5993
+ if (opTimeLabel) opTimeLabel.textContent = i18n.operation_time;
5994
+ opTimeVal.textContent = entityObject.operationHours ?? "-";
5995
+ }
5976
5996
  }
5977
5997
  const powerVal = root.querySelector(".myio-ho-card__footer .metric:nth-child(2) .val");
5978
5998
  if (powerVal) {
5979
5999
  if (entityObject.domain === "water") {
5980
6000
  const pulses = entityObject.pulses ?? 0;
5981
6001
  powerVal.textContent = `${pulses} L`;
6002
+ } else if (entityObject.domain === "temperature") {
6003
+ powerVal.textContent = entityObject.lastActivityTime ? formatRelativeTime2(entityObject.lastActivityTime) : "-";
5982
6004
  } else {
5983
6005
  const instantPower = entityObject.instantaneousPower ?? entityObject.consumption_power ?? null;
5984
6006
  const powerFormatted = formatPower(instantPower);
@@ -16457,35 +16479,72 @@ ${rangeText}`;
16457
16479
  }
16458
16480
 
16459
16481
  // src/components/premium-modals/power-limits/types.ts
16482
+ var DOMAINS = [
16483
+ { value: "energy", label: "Energia", icon: "\u26A1" },
16484
+ { value: "water", label: "\xC1gua", icon: "\u{1F4A7}" },
16485
+ { value: "temperature", label: "Temperatura", icon: "\u{1F321}\uFE0F" }
16486
+ ];
16460
16487
  var DEVICE_TYPES = [
16461
- { value: "ELEVADOR", label: "Elevator" },
16462
- { value: "ESCADA_ROLANTE", label: "Escalator" },
16488
+ { value: "ELEVADOR", label: "Elevador" },
16489
+ { value: "ESCADA_ROLANTE", label: "Escada Rolante" },
16463
16490
  { value: "MOTOR", label: "Motor" },
16464
- { value: "BOMBA", label: "Pump" },
16491
+ { value: "BOMBA", label: "Bomba" },
16465
16492
  { value: "CHILLER", label: "Chiller" },
16466
- { value: "AR_CONDICIONADO", label: "Air Conditioner" },
16493
+ { value: "AR_CONDICIONADO", label: "Ar Condicionado" },
16467
16494
  { value: "HVAC", label: "HVAC" },
16468
16495
  { value: "FANCOIL", label: "Fancoil" },
16469
- { value: "3F_MEDIDOR", label: "Three-phase Meter" }
16496
+ { value: "3F_MEDIDOR", label: "Medidor Trif\xE1sico" }
16470
16497
  ];
16471
16498
  var TELEMETRY_TYPES2 = [
16472
- { value: "consumption", label: "Consumption (kW)", unit: "kW" },
16473
- { value: "voltage_a", label: "Voltage A (V)", unit: "V" },
16474
- { value: "voltage_b", label: "Voltage B (V)", unit: "V" },
16475
- { value: "voltage_c", label: "Voltage C (V)", unit: "V" },
16476
- { value: "current_a", label: "Current A (A)", unit: "A" },
16477
- { value: "current_b", label: "Current B (A)", unit: "A" },
16478
- { value: "current_c", label: "Current C (A)", unit: "A" },
16479
- { value: "total_current", label: "Total Current (A)", unit: "A" },
16480
- { value: "fp_a", label: "Power Factor A", unit: "" },
16481
- { value: "fp_b", label: "Power Factor B", unit: "" },
16482
- { value: "fp_c", label: "Power Factor C", unit: "" }
16499
+ { value: "consumption", label: "Pot\xEAncia (kW)", unit: "kW" },
16500
+ { value: "voltage_a", label: "Tens\xE3o A (V)", unit: "V" },
16501
+ { value: "voltage_b", label: "Tens\xE3o B (V)", unit: "V" },
16502
+ { value: "voltage_c", label: "Tens\xE3o C (V)", unit: "V" },
16503
+ { value: "current_a", label: "Corrente A (A)", unit: "A" },
16504
+ { value: "current_b", label: "Corrente B (A)", unit: "A" },
16505
+ { value: "current_c", label: "Corrente C (A)", unit: "A" },
16506
+ { value: "total_current", label: "Corrente Total (A)", unit: "A" },
16507
+ { value: "fp_a", label: "Fator de Pot\xEAncia A", unit: "" },
16508
+ { value: "fp_b", label: "Fator de Pot\xEAncia B", unit: "" },
16509
+ { value: "fp_c", label: "Fator de Pot\xEAncia C", unit: "" }
16483
16510
  ];
16511
+ var STATUS_ICONS = {
16512
+ energy: {
16513
+ standBy: "\u{1F50C}",
16514
+ // STANDBY
16515
+ normal: "\u26A1",
16516
+ // POWER_ON
16517
+ alert: "\u26A0\uFE0F",
16518
+ // WARNING
16519
+ failure: "\u{1F6A8}"
16520
+ // FAILURE
16521
+ },
16522
+ water: {
16523
+ standBy: "\u{1F6B0}",
16524
+ // STANDBY
16525
+ normal: "\u{1F4A7}",
16526
+ // POWER_ON
16527
+ alert: "\u26A0\uFE0F",
16528
+ // WARNING
16529
+ failure: "\u{1F6A8}"
16530
+ // FAILURE
16531
+ },
16532
+ temperature: {
16533
+ standBy: "\u{1F321}\uFE0F",
16534
+ // STANDBY
16535
+ normal: "\u{1F321}\uFE0F",
16536
+ // POWER_ON
16537
+ alert: "\u26A0\uFE0F",
16538
+ // WARNING
16539
+ failure: "\u{1F6A8}"
16540
+ // FAILURE
16541
+ }
16542
+ };
16484
16543
  var STATUS_CONFIG = {
16485
16544
  standBy: { label: "StandBy", color: "#22c55e", bgColor: "rgba(34, 197, 94, 0.1)" },
16486
16545
  normal: { label: "Normal", color: "#3b82f6", bgColor: "rgba(59, 130, 246, 0.1)" },
16487
- alert: { label: "Alert", color: "#f59e0b", bgColor: "rgba(245, 158, 11, 0.1)" },
16488
- failure: { label: "Failure", color: "#ef4444", bgColor: "rgba(239, 68, 68, 0.1)" }
16546
+ alert: { label: "Alerta", color: "#f59e0b", bgColor: "rgba(245, 158, 11, 0.1)" },
16547
+ failure: { label: "Falha", color: "#ef4444", bgColor: "rgba(239, 68, 68, 0.1)" }
16489
16548
  };
16490
16549
 
16491
16550
  // src/components/premium-modals/power-limits/PowerLimitsModalView.ts
@@ -16501,12 +16560,43 @@ ${rangeText}`;
16501
16560
  this.formData = {
16502
16561
  deviceType: config.deviceType,
16503
16562
  telemetryType: config.telemetryType,
16563
+ domain: config.domain,
16504
16564
  standby: { baseValue: null, topValue: null },
16505
16565
  normal: { baseValue: null, topValue: null },
16506
16566
  alert: { baseValue: null, topValue: null },
16507
16567
  failure: { baseValue: null, topValue: null }
16508
16568
  };
16509
16569
  }
16570
+ // Format number with thousand separator (.) and up to 2 decimal places
16571
+ formatNumberForDisplay(value) {
16572
+ if (value === null || value === void 0) return "";
16573
+ const parts = value.toFixed(2).split(".");
16574
+ parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ".");
16575
+ return parts.join(",");
16576
+ }
16577
+ // Parse formatted string back to number
16578
+ parseFormattedNumber(value) {
16579
+ if (!value || value.trim() === "") return null;
16580
+ const normalized = value.replace(/\./g, "").replace(",", ".");
16581
+ const num = parseFloat(normalized);
16582
+ return isNaN(num) ? null : num;
16583
+ }
16584
+ // Handle input formatting on blur
16585
+ formatInputValue(input) {
16586
+ const rawValue = input.value;
16587
+ const parsed = this.parseFormattedNumber(rawValue);
16588
+ if (parsed !== null) {
16589
+ input.value = this.formatNumberForDisplay(parsed);
16590
+ }
16591
+ }
16592
+ // Handle input on focus - show raw value for editing
16593
+ unformatInputValue(input) {
16594
+ const formatted = input.value;
16595
+ const parsed = this.parseFormattedNumber(formatted);
16596
+ if (parsed !== null) {
16597
+ input.value = parsed.toString().replace(".", ",");
16598
+ }
16599
+ }
16510
16600
  render(targetContainer) {
16511
16601
  this.overlayEl = document.createElement("div");
16512
16602
  this.overlayEl.className = "myio-power-limits-overlay";
@@ -16516,6 +16606,7 @@ ${rangeText}`;
16516
16606
  ${this.renderHeader()}
16517
16607
  ${this.renderSelectors()}
16518
16608
  ${this.renderStatusCards()}
16609
+ ${this.renderToolbar()}
16519
16610
  ${this.renderLoadingState()}
16520
16611
  ${this.renderErrorState()}
16521
16612
  ${this.renderSuccessState()}
@@ -16532,80 +16623,107 @@ ${rangeText}`;
16532
16623
  }
16533
16624
  renderHeader() {
16534
16625
  return `
16535
- <div class="myio-power-limits-header">
16536
- <div class="myio-power-limits-title-section">
16537
- <span class="myio-power-limits-icon">&#x2699;</span>
16538
- <h2 class="myio-power-limits-title">Power Limits Setup</h2>
16539
- </div>
16540
- <div class="myio-power-limits-actions">
16626
+ <div class="myio-modal-header">
16627
+ <h2 class="myio-modal-title">\u2699\uFE0F Configura\xE7\xE3o de Limites</h2>
16628
+ <button class="myio-modal-close" id="plm-close-btn" type="button" aria-label="Fechar modal">\xD7</button>
16629
+ </div>
16630
+ `;
16631
+ }
16632
+ renderToolbar() {
16633
+ return `
16634
+ <div class="myio-power-limits-toolbar">
16635
+ <div class="myio-toolbar-actions">
16636
+ <button class="myio-btn myio-btn-secondary" id="plm-reset-btn" type="button">Limpar</button>
16541
16637
  <button class="myio-btn myio-btn-primary" id="plm-save-btn" type="button">
16542
- <span class="myio-btn-text">Save</span>
16638
+ <span class="myio-btn-text">Salvar</span>
16543
16639
  <span class="myio-btn-spinner" style="display: none;"></span>
16544
16640
  </button>
16545
- <button class="myio-btn myio-btn-secondary" id="plm-reset-btn" type="button">Reset</button>
16546
- <button class="myio-btn myio-btn-close" id="plm-close-btn" type="button" aria-label="Close">&times;</button>
16547
16641
  </div>
16548
16642
  </div>
16549
16643
  `;
16550
16644
  }
16551
16645
  renderSelectors() {
16552
- const deviceOptions = DEVICE_TYPES.map(
16553
- (dt) => `<option value="${dt.value}" ${dt.value === this.config.deviceType ? "selected" : ""}>${dt.label}</option>`
16554
- ).join("");
16555
- const telemetryOptions = TELEMETRY_TYPES2.map(
16556
- (tt) => `<option value="${tt.value}" ${tt.value === this.config.telemetryType ? "selected" : ""}>${tt.label}</option>`
16646
+ const domain = this.formData.domain || "energy";
16647
+ const domainOptions = DOMAINS.map(
16648
+ (d) => `<option value="${d.value}" ${d.value === domain ? "selected" : ""}>${d.icon} ${d.label}</option>`
16557
16649
  ).join("");
16650
+ let deviceTypeContent;
16651
+ let telemetryLabel;
16652
+ switch (domain) {
16653
+ case "temperature":
16654
+ deviceTypeContent = `<div class="myio-fixed-value">Sensor de Temperatura</div>`;
16655
+ telemetryLabel = "Temperatura em Celsius";
16656
+ break;
16657
+ case "water":
16658
+ deviceTypeContent = `<div class="myio-fixed-value">Hidr\xF4metro</div>`;
16659
+ telemetryLabel = "Litros";
16660
+ break;
16661
+ case "energy":
16662
+ default:
16663
+ deviceTypeContent = `<select id="plm-device-type" class="myio-select">
16664
+ ${DEVICE_TYPES.map(
16665
+ (dt) => `<option value="${dt.value}" ${dt.value === this.formData.deviceType ? "selected" : ""}>${dt.label}</option>`
16666
+ ).join("")}
16667
+ </select>`;
16668
+ telemetryLabel = "Pot\xEAncia (kW)";
16669
+ break;
16670
+ }
16558
16671
  return `
16559
16672
  <div class="myio-power-limits-selectors">
16560
16673
  <div class="myio-form-group">
16561
- <label for="plm-device-type">Device Type</label>
16562
- <select id="plm-device-type" class="myio-select">
16563
- ${deviceOptions}
16674
+ <label for="plm-domain">Dom\xEDnio</label>
16675
+ <select id="plm-domain" class="myio-select">
16676
+ ${domainOptions}
16564
16677
  </select>
16565
16678
  </div>
16566
16679
  <div class="myio-form-group">
16567
- <label for="plm-telemetry-type">Telemetry Type</label>
16568
- <select id="plm-telemetry-type" class="myio-select">
16569
- ${telemetryOptions}
16570
- </select>
16680
+ <label>Tipo de Dispositivo</label>
16681
+ ${deviceTypeContent}
16682
+ </div>
16683
+ <div class="myio-form-group">
16684
+ <label>Tipo de Telemetria</label>
16685
+ <div class="myio-fixed-value">${telemetryLabel}</div>
16571
16686
  </div>
16572
16687
  </div>
16573
16688
  `;
16574
16689
  }
16575
16690
  renderStatusCards() {
16576
16691
  const statuses = ["standby", "normal", "alert", "failure"];
16692
+ const domain = this.formData.domain || "energy";
16693
+ const domainIcons = STATUS_ICONS[domain];
16577
16694
  const cards = statuses.map((status) => {
16578
- const config = STATUS_CONFIG[status === "standby" ? "standBy" : status];
16695
+ const statusKey = status === "standby" ? "standBy" : status;
16696
+ const config = STATUS_CONFIG[statusKey];
16579
16697
  const formValues = this.formData[status];
16698
+ const icon = domainIcons[statusKey];
16580
16699
  return `
16581
16700
  <div class="myio-power-limits-card-item myio-status-${status}" style="--status-color: ${config.color}; --status-bg: ${config.bgColor};">
16582
16701
  <div class="myio-card-header">
16702
+ <span class="myio-status-icon">${icon}</span>
16583
16703
  <span class="myio-status-indicator"></span>
16584
16704
  <span class="myio-status-label">${config.label}</span>
16585
16705
  </div>
16586
16706
  <div class="myio-card-inputs">
16587
16707
  <div class="myio-input-group">
16588
- <label for="plm-${status}-base">Base Value</label>
16708
+ <label for="plm-${status}-base">Limite Inferior</label>
16589
16709
  <input
16590
- type="number"
16710
+ type="text"
16591
16711
  id="plm-${status}-base"
16592
- class="myio-input"
16593
- min="0"
16594
- step="0.01"
16595
- value="${formValues.baseValue ?? ""}"
16596
- placeholder="0"
16712
+ class="myio-input myio-formatted-number"
16713
+ inputmode="decimal"
16714
+ value="${this.formatNumberForDisplay(formValues.baseValue)}"
16715
+ placeholder="0,00"
16597
16716
  >
16598
16717
  </div>
16599
16718
  <div class="myio-input-group">
16600
- <label for="plm-${status}-top">Top Value</label>
16719
+ <label for="plm-${status}-top">Limite Superior</label>
16601
16720
  <input
16602
- type="number"
16721
+ type="text"
16603
16722
  id="plm-${status}-top"
16604
- class="myio-input"
16605
- min="0"
16606
- step="0.01"
16607
- value="${formValues.topValue ?? ""}"
16608
- placeholder="0"
16723
+ class="myio-input myio-formatted-number"
16724
+ inputmode="decimal"
16725
+ value="${this.formatNumberForDisplay(formValues.topValue)}"
16726
+ placeholder="0,00"
16609
16727
  >
16610
16728
  </div>
16611
16729
  </div>
@@ -16622,7 +16740,7 @@ ${rangeText}`;
16622
16740
  return `
16623
16741
  <div class="myio-power-limits-loading" id="plm-loading" style="display: none;">
16624
16742
  <div class="myio-spinner"></div>
16625
- <span>Loading configuration...</span>
16743
+ <span>Carregando configura\xE7\xE3o...</span>
16626
16744
  </div>
16627
16745
  `;
16628
16746
  }
@@ -16638,7 +16756,7 @@ ${rangeText}`;
16638
16756
  return `
16639
16757
  <div class="myio-power-limits-success" id="plm-success" style="display: none;">
16640
16758
  <span class="myio-success-icon">&#x2713;</span>
16641
- <span class="myio-success-message">Configuration saved successfully!</span>
16759
+ <span class="myio-success-message">Configura\xE7\xE3o salva com sucesso!</span>
16642
16760
  </div>
16643
16761
  `;
16644
16762
  }
@@ -16656,31 +16774,121 @@ ${rangeText}`;
16656
16774
  saveBtn?.addEventListener("click", () => this.handleSave());
16657
16775
  const resetBtn = this.overlayEl.querySelector("#plm-reset-btn");
16658
16776
  resetBtn?.addEventListener("click", () => this.handleReset());
16659
- const deviceSelect = this.overlayEl.querySelector("#plm-device-type");
16660
- deviceSelect?.addEventListener("change", (e) => {
16661
- const value = e.target.value;
16662
- this.formData.deviceType = value;
16663
- this.config.onDeviceTypeChange(value);
16664
- });
16665
- const telemetrySelect = this.overlayEl.querySelector("#plm-telemetry-type");
16666
- telemetrySelect?.addEventListener("change", (e) => {
16777
+ const domainSelect = this.overlayEl.querySelector("#plm-domain");
16778
+ domainSelect?.addEventListener("change", (e) => {
16667
16779
  const value = e.target.value;
16668
- this.formData.telemetryType = value;
16669
- this.config.onTelemetryTypeChange(value);
16780
+ this.formData.domain = value;
16781
+ switch (value) {
16782
+ case "temperature":
16783
+ this.formData.deviceType = "SENSOR_TEMPERATURA";
16784
+ this.formData.telemetryType = "temperature";
16785
+ break;
16786
+ case "water":
16787
+ this.formData.deviceType = "HIDROMETRO";
16788
+ this.formData.telemetryType = "liters";
16789
+ break;
16790
+ case "energy":
16791
+ default:
16792
+ this.formData.telemetryType = "consumption";
16793
+ break;
16794
+ }
16795
+ this.config.onDomainChange(value);
16796
+ this.updateSelectorsUI();
16797
+ this.updateStatusIcons();
16670
16798
  });
16799
+ this.setupDeviceTypeListener();
16671
16800
  const statuses = ["standby", "normal", "alert", "failure"];
16672
16801
  statuses.forEach((status) => {
16673
16802
  const baseInput = this.overlayEl?.querySelector(`#plm-${status}-base`);
16674
16803
  const topInput = this.overlayEl?.querySelector(`#plm-${status}-top`);
16675
- baseInput?.addEventListener("input", (e) => {
16804
+ if (baseInput) {
16805
+ baseInput.addEventListener("focus", () => this.unformatInputValue(baseInput));
16806
+ baseInput.addEventListener("blur", () => {
16807
+ this.formData[status].baseValue = this.parseFormattedNumber(baseInput.value);
16808
+ this.formatInputValue(baseInput);
16809
+ });
16810
+ baseInput.addEventListener("keydown", (e) => this.handleNumberKeydown(e));
16811
+ }
16812
+ if (topInput) {
16813
+ topInput.addEventListener("focus", () => this.unformatInputValue(topInput));
16814
+ topInput.addEventListener("blur", () => {
16815
+ this.formData[status].topValue = this.parseFormattedNumber(topInput.value);
16816
+ this.formatInputValue(topInput);
16817
+ });
16818
+ topInput.addEventListener("keydown", (e) => this.handleNumberKeydown(e));
16819
+ }
16820
+ });
16821
+ }
16822
+ // Handle keyboard input to allow only valid number characters
16823
+ handleNumberKeydown(e) {
16824
+ const allowedKeys = ["Backspace", "Delete", "ArrowLeft", "ArrowRight", "Tab", "Home", "End"];
16825
+ const isDigit = /^\d$/.test(e.key);
16826
+ const isComma = e.key === ",";
16827
+ const isAllowedKey = allowedKeys.includes(e.key);
16828
+ const hasCtrl = e.ctrlKey || e.metaKey;
16829
+ if (!isDigit && !isComma && !isAllowedKey && !hasCtrl) {
16830
+ e.preventDefault();
16831
+ }
16832
+ if (isComma) {
16833
+ const input = e.target;
16834
+ if (input.value.includes(",")) {
16835
+ e.preventDefault();
16836
+ }
16837
+ }
16838
+ }
16839
+ // Update status icons when domain changes
16840
+ updateStatusIcons() {
16841
+ const domain = this.formData.domain || "energy";
16842
+ const domainIcons = STATUS_ICONS[domain];
16843
+ const statuses = ["standby", "normal", "alert", "failure"];
16844
+ statuses.forEach((status) => {
16845
+ const statusKey = status === "standby" ? "standBy" : status;
16846
+ const iconEl = this.overlayEl?.querySelector(`.myio-status-${status} .myio-status-icon`);
16847
+ if (iconEl) {
16848
+ iconEl.textContent = domainIcons[statusKey];
16849
+ }
16850
+ });
16851
+ }
16852
+ // Update selectors UI when domain changes
16853
+ updateSelectorsUI() {
16854
+ const selectorsContainer = this.overlayEl?.querySelector(".myio-power-limits-selectors");
16855
+ if (selectorsContainer) {
16856
+ selectorsContainer.outerHTML = this.renderSelectors();
16857
+ const domainSelect = this.overlayEl?.querySelector("#plm-domain");
16858
+ domainSelect?.addEventListener("change", (e) => {
16676
16859
  const value = e.target.value;
16677
- this.formData[status].baseValue = value ? parseFloat(value) : null;
16860
+ this.formData.domain = value;
16861
+ switch (value) {
16862
+ case "temperature":
16863
+ this.formData.deviceType = "SENSOR_TEMPERATURA";
16864
+ this.formData.telemetryType = "temperature";
16865
+ break;
16866
+ case "water":
16867
+ this.formData.deviceType = "HIDROMETRO";
16868
+ this.formData.telemetryType = "liters";
16869
+ break;
16870
+ case "energy":
16871
+ default:
16872
+ this.formData.telemetryType = "consumption";
16873
+ break;
16874
+ }
16875
+ this.config.onDomainChange(value);
16876
+ this.updateSelectorsUI();
16877
+ this.updateStatusIcons();
16678
16878
  });
16679
- topInput?.addEventListener("input", (e) => {
16879
+ this.setupDeviceTypeListener();
16880
+ }
16881
+ }
16882
+ // Setup device type listener (only for energy/water domains)
16883
+ setupDeviceTypeListener() {
16884
+ const deviceSelect = this.overlayEl?.querySelector("#plm-device-type");
16885
+ if (deviceSelect) {
16886
+ deviceSelect.addEventListener("change", (e) => {
16680
16887
  const value = e.target.value;
16681
- this.formData[status].topValue = value ? parseFloat(value) : null;
16888
+ this.formData.deviceType = value;
16889
+ this.config.onDeviceTypeChange(value);
16682
16890
  });
16683
- });
16891
+ }
16684
16892
  }
16685
16893
  handleKeyDown = (e) => {
16686
16894
  if (e.key === "Escape") {
@@ -16703,7 +16911,7 @@ ${rangeText}`;
16703
16911
  this.showSuccess();
16704
16912
  setTimeout(() => this.hideSuccess(), 3e3);
16705
16913
  } catch (error) {
16706
- this.showError(error.message || "Failed to save configuration");
16914
+ this.showError(error.message || "Falha ao salvar configura\xE7\xE3o");
16707
16915
  } finally {
16708
16916
  this.isSaving = false;
16709
16917
  this.showSaveLoading(false);
@@ -16727,13 +16935,13 @@ ${rangeText}`;
16727
16935
  const base = this.formData[status].baseValue;
16728
16936
  const top = this.formData[status].topValue;
16729
16937
  if (base !== null && base < 0) {
16730
- return `${STATUS_CONFIG[status === "standby" ? "standBy" : status].label}: Base value cannot be negative`;
16938
+ return `${STATUS_CONFIG[status === "standby" ? "standBy" : status].label}: Limite inferior n\xE3o pode ser negativo`;
16731
16939
  }
16732
16940
  if (top !== null && top < 0) {
16733
- return `${STATUS_CONFIG[status === "standby" ? "standBy" : status].label}: Top value cannot be negative`;
16941
+ return `${STATUS_CONFIG[status === "standby" ? "standBy" : status].label}: Limite superior n\xE3o pode ser negativo`;
16734
16942
  }
16735
16943
  if (base !== null && top !== null && base > top) {
16736
- return `${STATUS_CONFIG[status === "standby" ? "standBy" : status].label}: Base value should not exceed top value`;
16944
+ return `${STATUS_CONFIG[status === "standby" ? "standBy" : status].label}: Limite inferior n\xE3o pode ser maior que o limite superior`;
16737
16945
  }
16738
16946
  }
16739
16947
  return null;
@@ -16802,11 +17010,13 @@ ${rangeText}`;
16802
17010
  setFormData(data) {
16803
17011
  if (data.deviceType) this.formData.deviceType = data.deviceType;
16804
17012
  if (data.telemetryType) this.formData.telemetryType = data.telemetryType;
17013
+ if (data.domain) this.formData.domain = data.domain;
16805
17014
  if (data.standby) this.formData.standby = { ...data.standby };
16806
17015
  if (data.normal) this.formData.normal = { ...data.normal };
16807
17016
  if (data.alert) this.formData.alert = { ...data.alert };
16808
17017
  if (data.failure) this.formData.failure = { ...data.failure };
16809
17018
  this.updateInputValues();
17019
+ this.updateStatusIcons();
16810
17020
  }
16811
17021
  updateInputValues() {
16812
17022
  const statuses = ["standby", "normal", "alert", "failure"];
@@ -16814,16 +17024,16 @@ ${rangeText}`;
16814
17024
  const baseInput = this.overlayEl?.querySelector(`#plm-${status}-base`);
16815
17025
  const topInput = this.overlayEl?.querySelector(`#plm-${status}-top`);
16816
17026
  if (baseInput) {
16817
- baseInput.value = this.formData[status].baseValue?.toString() ?? "";
17027
+ baseInput.value = this.formatNumberForDisplay(this.formData[status].baseValue);
16818
17028
  }
16819
17029
  if (topInput) {
16820
- topInput.value = this.formData[status].topValue?.toString() ?? "";
17030
+ topInput.value = this.formatNumberForDisplay(this.formData[status].topValue);
16821
17031
  }
16822
17032
  });
17033
+ const domainSelect = this.overlayEl?.querySelector("#plm-domain");
16823
17034
  const deviceSelect = this.overlayEl?.querySelector("#plm-device-type");
16824
- const telemetrySelect = this.overlayEl?.querySelector("#plm-telemetry-type");
17035
+ if (domainSelect) domainSelect.value = this.formData.domain;
16825
17036
  if (deviceSelect) deviceSelect.value = this.formData.deviceType;
16826
- if (telemetrySelect) telemetrySelect.value = this.formData.telemetryType;
16827
17037
  }
16828
17038
  getStyles() {
16829
17039
  const styles = this.config.styles || {};
@@ -16847,7 +17057,7 @@ ${rangeText}`;
16847
17057
  opacity: 0;
16848
17058
  visibility: hidden;
16849
17059
  transition: all 0.3s ease;
16850
- font-family: ${styles.fontFamily || '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'};
17060
+ font-family: ${styles.fontFamily || "'Roboto', Arial, sans-serif"};
16851
17061
  }
16852
17062
 
16853
17063
  .myio-power-limits-overlay.active {
@@ -16857,9 +17067,9 @@ ${rangeText}`;
16857
17067
 
16858
17068
  .myio-power-limits-card {
16859
17069
  background: ${styles.backgroundColor || "#ffffff"};
16860
- border-radius: ${styles.borderRadius || "12px"};
17070
+ border-radius: ${styles.borderRadius || "10px"};
16861
17071
  width: 90%;
16862
- max-width: 875px;
17072
+ max-width: 1104px;
16863
17073
  max-height: 90vh;
16864
17074
  overflow-y: auto;
16865
17075
  transform: scale(0.9);
@@ -16871,36 +17081,55 @@ ${rangeText}`;
16871
17081
  transform: scale(1);
16872
17082
  }
16873
17083
 
16874
- .myio-power-limits-header {
17084
+ /* Header - ModalPremiumShell pattern */
17085
+ .myio-modal-header {
16875
17086
  display: flex;
16876
17087
  align-items: center;
16877
17088
  justify-content: space-between;
16878
- padding: 20px 24px;
16879
- background: linear-gradient(135deg, ${primaryColor}, ${this.lightenColor(primaryColor, 20)});
16880
- color: white;
16881
- border-radius: 12px 12px 0 0;
17089
+ padding: 4px 8px;
17090
+ background: ${primaryColor};
17091
+ border-radius: 10px 10px 0 0;
17092
+ min-height: 20px;
16882
17093
  }
16883
17094
 
16884
- .myio-power-limits-title-section {
16885
- display: flex;
16886
- align-items: center;
16887
- gap: 12px;
17095
+ .myio-modal-title {
17096
+ margin: 6px;
17097
+ font-size: 18px;
17098
+ font-weight: 600;
17099
+ color: white;
17100
+ line-height: 2;
16888
17101
  }
16889
17102
 
16890
- .myio-power-limits-icon {
17103
+ .myio-modal-close {
17104
+ background: none;
17105
+ border: none;
16891
17106
  font-size: 24px;
17107
+ cursor: pointer;
17108
+ padding: 4px 12px;
17109
+ border-radius: 6px;
17110
+ color: rgba(255, 255, 255, 0.8);
17111
+ transition: background-color 0.2s, color 0.2s;
17112
+ line-height: 1;
16892
17113
  }
16893
17114
 
16894
- .myio-power-limits-title {
16895
- font-size: 1.25rem;
16896
- font-weight: 600;
16897
- margin: 0;
17115
+ .myio-modal-close:hover {
17116
+ background-color: rgba(255, 255, 255, 0.2);
17117
+ color: white;
16898
17118
  }
16899
17119
 
16900
- .myio-power-limits-actions {
17120
+ /* Toolbar with Save/Reset buttons */
17121
+ .myio-power-limits-toolbar {
17122
+ display: flex;
17123
+ justify-content: flex-end;
17124
+ padding: 16px 24px;
17125
+ background: #f9fafb;
17126
+ border-top: 1px solid #e5e7eb;
17127
+ }
17128
+
17129
+ .myio-toolbar-actions {
16901
17130
  display: flex;
16902
17131
  align-items: center;
16903
- gap: 8px;
17132
+ gap: 12px;
16904
17133
  }
16905
17134
 
16906
17135
  .myio-btn {
@@ -16922,33 +17151,21 @@ ${rangeText}`;
16922
17151
  }
16923
17152
 
16924
17153
  .myio-btn-primary {
16925
- background: white;
16926
- color: ${primaryColor};
17154
+ background: ${primaryColor};
17155
+ color: white;
16927
17156
  }
16928
17157
 
16929
17158
  .myio-btn-primary:hover:not(:disabled) {
16930
- background: #f3f4f6;
17159
+ background: ${this.lightenColor(primaryColor, -10)};
16931
17160
  }
16932
17161
 
16933
17162
  .myio-btn-secondary {
16934
- background: rgba(255, 255, 255, 0.2);
16935
- color: white;
17163
+ background: #e5e7eb;
17164
+ color: #374151;
16936
17165
  }
16937
17166
 
16938
17167
  .myio-btn-secondary:hover:not(:disabled) {
16939
- background: rgba(255, 255, 255, 0.3);
16940
- }
16941
-
16942
- .myio-btn-close {
16943
- background: transparent;
16944
- color: white;
16945
- font-size: 24px;
16946
- padding: 4px 8px;
16947
- line-height: 1;
16948
- }
16949
-
16950
- .myio-btn-close:hover {
16951
- background: rgba(255, 255, 255, 0.1);
17168
+ background: #d1d5db;
16952
17169
  }
16953
17170
 
16954
17171
  .myio-btn-spinner {
@@ -16966,7 +17183,7 @@ ${rangeText}`;
16966
17183
 
16967
17184
  .myio-power-limits-selectors {
16968
17185
  display: grid;
16969
- grid-template-columns: 1fr 1fr;
17186
+ grid-template-columns: 1fr 1fr 1fr;
16970
17187
  gap: 16px;
16971
17188
  padding: 20px 24px;
16972
17189
  background: #f9fafb;
@@ -17001,6 +17218,15 @@ ${rangeText}`;
17001
17218
  box-shadow: 0 0 0 3px ${this.hexToRgba(primaryColor, 0.1)};
17002
17219
  }
17003
17220
 
17221
+ .myio-fixed-value {
17222
+ padding: 10px 12px;
17223
+ border: 1px solid #e5e7eb;
17224
+ border-radius: 6px;
17225
+ font-size: 14px;
17226
+ background: #f9fafb;
17227
+ color: #6b7280;
17228
+ }
17229
+
17004
17230
  .myio-power-limits-grid {
17005
17231
  display: grid;
17006
17232
  grid-template-columns: repeat(2, 1fr);
@@ -17029,6 +17255,11 @@ ${rangeText}`;
17029
17255
  margin-bottom: 12px;
17030
17256
  }
17031
17257
 
17258
+ .myio-status-icon {
17259
+ font-size: 18px;
17260
+ line-height: 1;
17261
+ }
17262
+
17032
17263
  .myio-status-indicator {
17033
17264
  width: 12px;
17034
17265
  height: 12px;
@@ -17219,6 +17450,8 @@ ${rangeText}`;
17219
17450
  const defaultFormData = {
17220
17451
  deviceType,
17221
17452
  telemetryType,
17453
+ domain: "energy",
17454
+ // Default to energy, will be overwritten by caller if needed
17222
17455
  standby: { baseValue: null, topValue: null },
17223
17456
  normal: { baseValue: null, topValue: null },
17224
17457
  alert: { baseValue: null, topValue: null },
@@ -17388,10 +17621,12 @@ ${rangeText}`;
17388
17621
  const persister = new PowerLimitsPersister(params.token, params.tbBaseUrl);
17389
17622
  let currentDeviceType = params.deviceType || "ELEVADOR";
17390
17623
  let currentTelemetryType = params.telemetryType || "consumption";
17624
+ let currentDomain = params.domain || "energy";
17391
17625
  let existingLimits = params.existingMapPower || null;
17392
17626
  const view = new PowerLimitsModalView({
17393
17627
  deviceType: currentDeviceType,
17394
17628
  telemetryType: currentTelemetryType,
17629
+ domain: currentDomain,
17395
17630
  styles: params.styles,
17396
17631
  locale: params.locale,
17397
17632
  onDeviceTypeChange: async (deviceType) => {
@@ -17402,6 +17637,9 @@ ${rangeText}`;
17402
17637
  currentTelemetryType = telemetryType;
17403
17638
  await loadFormData();
17404
17639
  },
17640
+ onDomainChange: (domain) => {
17641
+ currentDomain = domain;
17642
+ },
17405
17643
  onSave: async () => {
17406
17644
  const formData = view.getFormData();
17407
17645
  const updatedLimits = persister.mergeFormDataIntoLimits(existingLimits, formData);
@@ -17427,6 +17665,7 @@ ${rangeText}`;
17427
17665
  existingLimits = await persister.loadCustomerPowerLimits(params.customerId);
17428
17666
  }
17429
17667
  const formData = persister.extractFormData(existingLimits, currentDeviceType, currentTelemetryType);
17668
+ formData.domain = currentDomain;
17430
17669
  view.setFormData(formData);
17431
17670
  } catch (error) {
17432
17671
  console.error("[PowerLimitsSetupModal] Error loading form data:", error);