myio-js-library 0.1.141 → 0.1.142

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
@@ -655,6 +655,7 @@ __export(index_exports, {
655
655
  openRealTimeTelemetryModal: () => openRealTimeTelemetryModal,
656
656
  openTemperatureComparisonModal: () => openTemperatureComparisonModal,
657
657
  openTemperatureModal: () => openTemperatureModal,
658
+ openTemperatureSettingsModal: () => openTemperatureSettingsModal,
658
659
  parseInputDateToDate: () => parseInputDateToDate,
659
660
  renderCardComponent: () => renderCardComponent,
660
661
  renderCardComponentEnhanced: () => renderCardComponent2,
@@ -18255,13 +18256,13 @@ function openGoalsPanel(params) {
18255
18256
  function initializeModal() {
18256
18257
  if (data) {
18257
18258
  modalState.goalsData = data;
18258
- renderModal3();
18259
+ renderModal4();
18259
18260
  } else {
18260
- renderModal3();
18261
+ renderModal4();
18261
18262
  loadGoalsData();
18262
18263
  }
18263
18264
  }
18264
- function renderModal3() {
18265
+ function renderModal4() {
18265
18266
  const existing = document.getElementById("myio-goals-panel-modal");
18266
18267
  if (existing) {
18267
18268
  existing.remove();
@@ -20261,8 +20262,12 @@ function drawChart(modalId, state) {
20261
20262
  const paddingBottom = 55;
20262
20263
  const isPeriodsFiltered = state.selectedPeriods.length < 4 && state.selectedPeriods.length > 0;
20263
20264
  const values = chartData.map((d) => d.y);
20264
- const minY = Math.min(...values) - 1;
20265
- const maxY = Math.max(...values) + 1;
20265
+ const dataMin = Math.min(...values);
20266
+ const dataMax = Math.max(...values);
20267
+ const thresholdMin = state.temperatureMin !== null ? state.temperatureMin : dataMin;
20268
+ const thresholdMax = state.temperatureMax !== null ? state.temperatureMax : dataMax;
20269
+ const minY = Math.min(dataMin, thresholdMin) - 1;
20270
+ const maxY = Math.max(dataMax, thresholdMax) + 1;
20266
20271
  const chartWidth = width - paddingLeft - paddingRight;
20267
20272
  const chartHeight = height - paddingTop - paddingBottom;
20268
20273
  const scaleY = chartHeight / (maxY - minY || 1);
@@ -20603,8 +20608,10 @@ async function openTemperatureComparisonModal(params) {
20603
20608
  deviceData: [],
20604
20609
  isLoading: true,
20605
20610
  dateRangePicker: null,
20606
- selectedPeriods: ["madrugada", "manha", "tarde", "noite"]
20611
+ selectedPeriods: ["madrugada", "manha", "tarde", "noite"],
20607
20612
  // All periods selected by default
20613
+ temperatureMin: params.temperatureMin ?? null,
20614
+ temperatureMax: params.temperatureMax ?? null
20608
20615
  };
20609
20616
  const savedGranularity = localStorage.getItem("myio-temp-comparison-granularity");
20610
20617
  const savedTheme = localStorage.getItem("myio-temp-comparison-theme");
@@ -21000,16 +21007,52 @@ function drawComparisonChart(modalId, state) {
21000
21007
  return;
21001
21008
  }
21002
21009
  const isPeriodsFiltered = state.selectedPeriods.length < 4 && state.selectedPeriods.length > 0;
21003
- let globalMinY = Infinity;
21004
- let globalMaxY = -Infinity;
21010
+ let dataMinY = Infinity;
21011
+ let dataMaxY = -Infinity;
21005
21012
  processedData.forEach(({ points }) => {
21006
21013
  points.forEach((point) => {
21007
- if (point.y < globalMinY) globalMinY = point.y;
21008
- if (point.y > globalMaxY) globalMaxY = point.y;
21014
+ if (point.y < dataMinY) dataMinY = point.y;
21015
+ if (point.y > dataMaxY) dataMaxY = point.y;
21016
+ });
21017
+ });
21018
+ const rangeMap = /* @__PURE__ */ new Map();
21019
+ state.deviceData.forEach((dd, index) => {
21020
+ const device = dd.device;
21021
+ const min = device.temperatureMin;
21022
+ const max = device.temperatureMax;
21023
+ if (min !== void 0 && min !== null && max !== void 0 && max !== null) {
21024
+ const key = `${min}-${max}`;
21025
+ if (!rangeMap.has(key)) {
21026
+ rangeMap.set(key, {
21027
+ min,
21028
+ max,
21029
+ customerName: device.customerName || "",
21030
+ color: CHART_COLORS[index % CHART_COLORS.length],
21031
+ deviceLabels: [device.label]
21032
+ });
21033
+ } else {
21034
+ rangeMap.get(key).deviceLabels.push(device.label);
21035
+ }
21036
+ }
21037
+ });
21038
+ if (rangeMap.size === 0 && state.temperatureMin !== null && state.temperatureMax !== null) {
21039
+ rangeMap.set("global", {
21040
+ min: state.temperatureMin,
21041
+ max: state.temperatureMax,
21042
+ customerName: "Global",
21043
+ color: colors.success,
21044
+ deviceLabels: []
21009
21045
  });
21046
+ }
21047
+ const temperatureRanges = Array.from(rangeMap.values());
21048
+ let thresholdMinY = dataMinY;
21049
+ let thresholdMaxY = dataMaxY;
21050
+ temperatureRanges.forEach((range) => {
21051
+ if (range.min < thresholdMinY) thresholdMinY = range.min;
21052
+ if (range.max > thresholdMaxY) thresholdMaxY = range.max;
21010
21053
  });
21011
- globalMinY = Math.floor(globalMinY) - 1;
21012
- globalMaxY = Math.ceil(globalMaxY) + 1;
21054
+ const globalMinY = Math.floor(Math.min(dataMinY, thresholdMinY)) - 1;
21055
+ const globalMaxY = Math.ceil(Math.max(dataMaxY, thresholdMaxY)) + 1;
21013
21056
  const chartWidth = width - paddingLeft - paddingRight;
21014
21057
  const chartHeight = height - paddingTop - paddingBottom;
21015
21058
  const scaleY = chartHeight / (globalMaxY - globalMinY || 1);
@@ -21049,6 +21092,41 @@ function drawComparisonChart(modalId, state) {
21049
21092
  ctx.lineTo(width - paddingRight, y);
21050
21093
  ctx.stroke();
21051
21094
  }
21095
+ const rangeColors = [
21096
+ { fill: "rgba(76, 175, 80, 0.12)", stroke: "#4CAF50" },
21097
+ // Green
21098
+ { fill: "rgba(33, 150, 243, 0.12)", stroke: "#2196F3" },
21099
+ // Blue
21100
+ { fill: "rgba(255, 152, 0, 0.12)", stroke: "#FF9800" },
21101
+ // Orange
21102
+ { fill: "rgba(156, 39, 176, 0.12)", stroke: "#9C27B0" }
21103
+ // Purple
21104
+ ];
21105
+ temperatureRanges.forEach((range, index) => {
21106
+ const rangeMinY = height - paddingBottom - (range.min - globalMinY) * scaleY;
21107
+ const rangeMaxY = height - paddingBottom - (range.max - globalMinY) * scaleY;
21108
+ const colorSet = rangeColors[index % rangeColors.length];
21109
+ ctx.fillStyle = colorSet.fill;
21110
+ ctx.fillRect(paddingLeft, rangeMaxY, chartWidth, rangeMinY - rangeMaxY);
21111
+ ctx.strokeStyle = colorSet.stroke;
21112
+ ctx.lineWidth = 1.5;
21113
+ ctx.setLineDash([6, 4]);
21114
+ ctx.beginPath();
21115
+ ctx.moveTo(paddingLeft, rangeMinY);
21116
+ ctx.lineTo(width - paddingRight, rangeMinY);
21117
+ ctx.moveTo(paddingLeft, rangeMaxY);
21118
+ ctx.lineTo(width - paddingRight, rangeMaxY);
21119
+ ctx.stroke();
21120
+ ctx.setLineDash([]);
21121
+ if (temperatureRanges.length > 1 || range.customerName) {
21122
+ ctx.fillStyle = colorSet.stroke;
21123
+ ctx.font = "10px system-ui, sans-serif";
21124
+ ctx.textAlign = "left";
21125
+ const labelY = (rangeMinY + rangeMaxY) / 2;
21126
+ const labelText = range.customerName || `${range.min}\xB0-${range.max}\xB0C`;
21127
+ ctx.fillText(labelText, width - paddingRight + 5, labelY + 3);
21128
+ }
21129
+ });
21052
21130
  processedData.forEach(({ device, points }) => {
21053
21131
  ctx.strokeStyle = device.color;
21054
21132
  ctx.lineWidth = 2.5;
@@ -21368,6 +21446,532 @@ function exportComparisonCSV(state) {
21368
21446
  document.body.removeChild(link);
21369
21447
  URL.revokeObjectURL(url);
21370
21448
  }
21449
+
21450
+ // src/components/temperature/TemperatureSettingsModal.ts
21451
+ var DARK_THEME2 = {
21452
+ modalBg: "linear-gradient(180deg, #1e1e2e 0%, #151521 100%)",
21453
+ headerBg: "#3e1a7d",
21454
+ textPrimary: "#ffffff",
21455
+ textSecondary: "rgba(255, 255, 255, 0.7)",
21456
+ textMuted: "rgba(255, 255, 255, 0.5)",
21457
+ inputBg: "rgba(255, 255, 255, 0.08)",
21458
+ inputBorder: "rgba(255, 255, 255, 0.2)",
21459
+ inputText: "#ffffff",
21460
+ buttonPrimary: "#3e1a7d",
21461
+ buttonPrimaryHover: "#5a2da8",
21462
+ buttonSecondary: "rgba(255, 255, 255, 0.1)",
21463
+ success: "#4CAF50",
21464
+ error: "#f44336",
21465
+ overlay: "rgba(0, 0, 0, 0.85)"
21466
+ };
21467
+ var LIGHT_THEME2 = {
21468
+ modalBg: "#ffffff",
21469
+ headerBg: "#3e1a7d",
21470
+ textPrimary: "#1a1a2e",
21471
+ textSecondary: "rgba(0, 0, 0, 0.7)",
21472
+ textMuted: "rgba(0, 0, 0, 0.5)",
21473
+ inputBg: "#f5f5f5",
21474
+ inputBorder: "rgba(0, 0, 0, 0.2)",
21475
+ inputText: "#1a1a2e",
21476
+ buttonPrimary: "#3e1a7d",
21477
+ buttonPrimaryHover: "#5a2da8",
21478
+ buttonSecondary: "rgba(0, 0, 0, 0.05)",
21479
+ success: "#4CAF50",
21480
+ error: "#f44336",
21481
+ overlay: "rgba(0, 0, 0, 0.5)"
21482
+ };
21483
+ function getColors(theme) {
21484
+ return theme === "dark" ? DARK_THEME2 : LIGHT_THEME2;
21485
+ }
21486
+ async function fetchCustomerAttributes(customerId, token) {
21487
+ const url = `/api/plugins/telemetry/CUSTOMER/${customerId}/values/attributes/SERVER_SCOPE`;
21488
+ const response = await fetch(url, {
21489
+ method: "GET",
21490
+ headers: {
21491
+ "Content-Type": "application/json",
21492
+ "X-Authorization": `Bearer ${token}`
21493
+ }
21494
+ });
21495
+ if (!response.ok) {
21496
+ if (response.status === 404 || response.status === 400) {
21497
+ return { minTemperature: null, maxTemperature: null };
21498
+ }
21499
+ throw new Error(`Failed to fetch attributes: ${response.status}`);
21500
+ }
21501
+ const attributes = await response.json();
21502
+ let minTemperature = null;
21503
+ let maxTemperature = null;
21504
+ if (Array.isArray(attributes)) {
21505
+ for (const attr of attributes) {
21506
+ if (attr.key === "minTemperature") {
21507
+ minTemperature = Number(attr.value);
21508
+ } else if (attr.key === "maxTemperature") {
21509
+ maxTemperature = Number(attr.value);
21510
+ }
21511
+ }
21512
+ }
21513
+ return { minTemperature, maxTemperature };
21514
+ }
21515
+ async function saveCustomerAttributes(customerId, token, minTemperature, maxTemperature) {
21516
+ const url = `/api/plugins/telemetry/CUSTOMER/${customerId}/SERVER_SCOPE`;
21517
+ const attributes = {
21518
+ minTemperature,
21519
+ maxTemperature
21520
+ };
21521
+ const response = await fetch(url, {
21522
+ method: "POST",
21523
+ headers: {
21524
+ "Content-Type": "application/json",
21525
+ "X-Authorization": `Bearer ${token}`
21526
+ },
21527
+ body: JSON.stringify(attributes)
21528
+ });
21529
+ if (!response.ok) {
21530
+ throw new Error(`Failed to save attributes: ${response.status}`);
21531
+ }
21532
+ }
21533
+ function renderModal3(container, state, modalId, onClose, onSave) {
21534
+ const colors = getColors(state.theme);
21535
+ const minValue = state.minTemperature !== null ? state.minTemperature : "";
21536
+ const maxValue = state.maxTemperature !== null ? state.maxTemperature : "";
21537
+ container.innerHTML = `
21538
+ <style>
21539
+ @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
21540
+ @keyframes slideIn { from { transform: translateY(-20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
21541
+ @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
21542
+
21543
+ #${modalId} {
21544
+ position: fixed;
21545
+ top: 0;
21546
+ left: 0;
21547
+ width: 100%;
21548
+ height: 100%;
21549
+ background: ${colors.overlay};
21550
+ z-index: 10000;
21551
+ display: flex;
21552
+ align-items: center;
21553
+ justify-content: center;
21554
+ animation: fadeIn 0.2s ease-out;
21555
+ }
21556
+
21557
+ #${modalId} .modal-content {
21558
+ background: ${colors.modalBg};
21559
+ border-radius: 16px;
21560
+ width: 90%;
21561
+ max-width: 480px;
21562
+ box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
21563
+ border: 1px solid rgba(255, 255, 255, 0.1);
21564
+ animation: slideIn 0.3s ease-out;
21565
+ overflow: hidden;
21566
+ }
21567
+
21568
+ #${modalId} .modal-header {
21569
+ background: ${colors.headerBg};
21570
+ padding: 20px 24px;
21571
+ display: flex;
21572
+ align-items: center;
21573
+ justify-content: space-between;
21574
+ }
21575
+
21576
+ #${modalId} .modal-title {
21577
+ margin: 0;
21578
+ font-size: 18px;
21579
+ font-weight: 600;
21580
+ color: #fff;
21581
+ font-family: 'Roboto', sans-serif;
21582
+ display: flex;
21583
+ align-items: center;
21584
+ gap: 10px;
21585
+ }
21586
+
21587
+ #${modalId} .close-btn {
21588
+ width: 32px;
21589
+ height: 32px;
21590
+ background: rgba(255, 255, 255, 0.1);
21591
+ border: 1px solid rgba(255, 255, 255, 0.2);
21592
+ border-radius: 8px;
21593
+ cursor: pointer;
21594
+ display: flex;
21595
+ align-items: center;
21596
+ justify-content: center;
21597
+ transition: all 0.2s;
21598
+ color: #fff;
21599
+ font-size: 18px;
21600
+ }
21601
+
21602
+ #${modalId} .close-btn:hover {
21603
+ background: rgba(255, 68, 68, 0.25);
21604
+ border-color: rgba(255, 68, 68, 0.5);
21605
+ }
21606
+
21607
+ #${modalId} .modal-body {
21608
+ padding: 24px;
21609
+ }
21610
+
21611
+ #${modalId} .customer-info {
21612
+ margin-bottom: 24px;
21613
+ padding: 12px 16px;
21614
+ background: ${colors.inputBg};
21615
+ border-radius: 8px;
21616
+ border: 1px solid ${colors.inputBorder};
21617
+ }
21618
+
21619
+ #${modalId} .customer-label {
21620
+ font-size: 12px;
21621
+ color: ${colors.textMuted};
21622
+ margin-bottom: 4px;
21623
+ }
21624
+
21625
+ #${modalId} .customer-name {
21626
+ font-size: 16px;
21627
+ font-weight: 500;
21628
+ color: ${colors.textPrimary};
21629
+ }
21630
+
21631
+ #${modalId} .form-group {
21632
+ margin-bottom: 20px;
21633
+ }
21634
+
21635
+ #${modalId} .form-label {
21636
+ display: block;
21637
+ font-size: 14px;
21638
+ font-weight: 500;
21639
+ color: ${colors.textSecondary};
21640
+ margin-bottom: 8px;
21641
+ }
21642
+
21643
+ #${modalId} .form-input {
21644
+ width: 100%;
21645
+ padding: 12px 16px;
21646
+ font-size: 16px;
21647
+ background: ${colors.inputBg};
21648
+ border: 1px solid ${colors.inputBorder};
21649
+ border-radius: 8px;
21650
+ color: ${colors.inputText};
21651
+ outline: none;
21652
+ transition: border-color 0.2s;
21653
+ box-sizing: border-box;
21654
+ }
21655
+
21656
+ #${modalId} .form-input:focus {
21657
+ border-color: ${colors.buttonPrimary};
21658
+ }
21659
+
21660
+ #${modalId} .form-input::placeholder {
21661
+ color: ${colors.textMuted};
21662
+ }
21663
+
21664
+ #${modalId} .form-hint {
21665
+ font-size: 12px;
21666
+ color: ${colors.textMuted};
21667
+ margin-top: 6px;
21668
+ }
21669
+
21670
+ #${modalId} .temperature-range {
21671
+ display: grid;
21672
+ grid-template-columns: 1fr 1fr;
21673
+ gap: 16px;
21674
+ }
21675
+
21676
+ #${modalId} .range-preview {
21677
+ margin-top: 20px;
21678
+ padding: 16px;
21679
+ background: rgba(76, 175, 80, 0.1);
21680
+ border: 1px dashed ${colors.success};
21681
+ border-radius: 8px;
21682
+ text-align: center;
21683
+ }
21684
+
21685
+ #${modalId} .range-preview-label {
21686
+ font-size: 12px;
21687
+ color: ${colors.textMuted};
21688
+ margin-bottom: 8px;
21689
+ }
21690
+
21691
+ #${modalId} .range-preview-value {
21692
+ font-size: 24px;
21693
+ font-weight: 600;
21694
+ color: ${colors.success};
21695
+ }
21696
+
21697
+ #${modalId} .modal-footer {
21698
+ padding: 16px 24px;
21699
+ border-top: 1px solid ${colors.inputBorder};
21700
+ display: flex;
21701
+ justify-content: flex-end;
21702
+ gap: 12px;
21703
+ }
21704
+
21705
+ #${modalId} .btn {
21706
+ padding: 10px 24px;
21707
+ font-size: 14px;
21708
+ font-weight: 500;
21709
+ border-radius: 8px;
21710
+ cursor: pointer;
21711
+ transition: all 0.2s;
21712
+ border: none;
21713
+ display: flex;
21714
+ align-items: center;
21715
+ gap: 8px;
21716
+ }
21717
+
21718
+ #${modalId} .btn-secondary {
21719
+ background: ${colors.buttonSecondary};
21720
+ color: ${colors.textSecondary};
21721
+ border: 1px solid ${colors.inputBorder};
21722
+ }
21723
+
21724
+ #${modalId} .btn-secondary:hover {
21725
+ background: ${colors.inputBg};
21726
+ }
21727
+
21728
+ #${modalId} .btn-primary {
21729
+ background: ${colors.buttonPrimary};
21730
+ color: #fff;
21731
+ }
21732
+
21733
+ #${modalId} .btn-primary:hover {
21734
+ background: ${colors.buttonPrimaryHover};
21735
+ }
21736
+
21737
+ #${modalId} .btn-primary:disabled {
21738
+ opacity: 0.6;
21739
+ cursor: not-allowed;
21740
+ }
21741
+
21742
+ #${modalId} .spinner {
21743
+ width: 16px;
21744
+ height: 16px;
21745
+ border: 2px solid rgba(255,255,255,0.3);
21746
+ border-top-color: #fff;
21747
+ border-radius: 50%;
21748
+ animation: spin 1s linear infinite;
21749
+ }
21750
+
21751
+ #${modalId} .message {
21752
+ padding: 12px 16px;
21753
+ border-radius: 8px;
21754
+ margin-bottom: 16px;
21755
+ font-size: 14px;
21756
+ }
21757
+
21758
+ #${modalId} .message-error {
21759
+ background: rgba(244, 67, 54, 0.1);
21760
+ border: 1px solid ${colors.error};
21761
+ color: ${colors.error};
21762
+ }
21763
+
21764
+ #${modalId} .message-success {
21765
+ background: rgba(76, 175, 80, 0.1);
21766
+ border: 1px solid ${colors.success};
21767
+ color: ${colors.success};
21768
+ }
21769
+
21770
+ #${modalId} .loading-overlay {
21771
+ display: flex;
21772
+ flex-direction: column;
21773
+ align-items: center;
21774
+ justify-content: center;
21775
+ padding: 48px;
21776
+ color: ${colors.textSecondary};
21777
+ }
21778
+
21779
+ #${modalId} .loading-spinner {
21780
+ width: 40px;
21781
+ height: 40px;
21782
+ border: 3px solid ${colors.inputBorder};
21783
+ border-top-color: ${colors.buttonPrimary};
21784
+ border-radius: 50%;
21785
+ animation: spin 1s linear infinite;
21786
+ margin-bottom: 16px;
21787
+ }
21788
+ </style>
21789
+
21790
+ <div id="${modalId}" class="modal-overlay">
21791
+ <div class="modal-content">
21792
+ <div class="modal-header">
21793
+ <h2 class="modal-title">
21794
+ <span>\u{1F321}\uFE0F</span>
21795
+ Configurar Temperatura
21796
+ </h2>
21797
+ <button class="close-btn" id="${modalId}-close">&times;</button>
21798
+ </div>
21799
+
21800
+ <div class="modal-body">
21801
+ ${state.isLoading ? `
21802
+ <div class="loading-overlay">
21803
+ <div class="loading-spinner"></div>
21804
+ <div>Carregando configura\xE7\xF5es...</div>
21805
+ </div>
21806
+ ` : `
21807
+ ${state.error ? `
21808
+ <div class="message message-error">${state.error}</div>
21809
+ ` : ""}
21810
+
21811
+ ${state.successMessage ? `
21812
+ <div class="message message-success">${state.successMessage}</div>
21813
+ ` : ""}
21814
+
21815
+ <div class="customer-info">
21816
+ <div class="customer-label">Shopping / Cliente</div>
21817
+ <div class="customer-name">${state.customerName || "N\xE3o identificado"}</div>
21818
+ </div>
21819
+
21820
+ <div class="form-group">
21821
+ <label class="form-label">Faixa de Temperatura Ideal</label>
21822
+ <div class="temperature-range">
21823
+ <div>
21824
+ <input
21825
+ type="number"
21826
+ id="${modalId}-min"
21827
+ class="form-input"
21828
+ placeholder="M\xEDnima"
21829
+ value="${minValue}"
21830
+ step="0.5"
21831
+ min="0"
21832
+ max="50"
21833
+ />
21834
+ <div class="form-hint">Temperatura m\xEDnima (\xB0C)</div>
21835
+ </div>
21836
+ <div>
21837
+ <input
21838
+ type="number"
21839
+ id="${modalId}-max"
21840
+ class="form-input"
21841
+ placeholder="M\xE1xima"
21842
+ value="${maxValue}"
21843
+ step="0.5"
21844
+ min="0"
21845
+ max="50"
21846
+ />
21847
+ <div class="form-hint">Temperatura m\xE1xima (\xB0C)</div>
21848
+ </div>
21849
+ </div>
21850
+ </div>
21851
+
21852
+ <div class="range-preview" id="${modalId}-preview">
21853
+ <div class="range-preview-label">Faixa configurada</div>
21854
+ <div class="range-preview-value" id="${modalId}-preview-value">
21855
+ ${minValue && maxValue ? `${minValue}\xB0C - ${maxValue}\xB0C` : "N\xE3o definida"}
21856
+ </div>
21857
+ </div>
21858
+ `}
21859
+ </div>
21860
+
21861
+ ${!state.isLoading ? `
21862
+ <div class="modal-footer">
21863
+ <button class="btn btn-secondary" id="${modalId}-cancel">Cancelar</button>
21864
+ <button class="btn btn-primary" id="${modalId}-save" ${state.isSaving ? "disabled" : ""}>
21865
+ ${state.isSaving ? '<div class="spinner"></div> Salvando...' : "Salvar"}
21866
+ </button>
21867
+ </div>
21868
+ ` : ""}
21869
+ </div>
21870
+ </div>
21871
+ `;
21872
+ const closeBtn = document.getElementById(`${modalId}-close`);
21873
+ const cancelBtn = document.getElementById(`${modalId}-cancel`);
21874
+ const saveBtn = document.getElementById(`${modalId}-save`);
21875
+ const minInput = document.getElementById(`${modalId}-min`);
21876
+ const maxInput = document.getElementById(`${modalId}-max`);
21877
+ const previewValue = document.getElementById(`${modalId}-preview-value`);
21878
+ const overlay = document.getElementById(modalId);
21879
+ closeBtn?.addEventListener("click", onClose);
21880
+ cancelBtn?.addEventListener("click", onClose);
21881
+ overlay?.addEventListener("click", (e) => {
21882
+ if (e.target === overlay) onClose();
21883
+ });
21884
+ const updatePreview = () => {
21885
+ if (previewValue && minInput && maxInput) {
21886
+ const min = minInput.value;
21887
+ const max = maxInput.value;
21888
+ if (min && max) {
21889
+ previewValue.textContent = `${min}\xB0C - ${max}\xB0C`;
21890
+ } else {
21891
+ previewValue.textContent = "N\xE3o definida";
21892
+ }
21893
+ }
21894
+ };
21895
+ minInput?.addEventListener("input", updatePreview);
21896
+ maxInput?.addEventListener("input", updatePreview);
21897
+ saveBtn?.addEventListener("click", async () => {
21898
+ if (!minInput || !maxInput) return;
21899
+ const min = parseFloat(minInput.value);
21900
+ const max = parseFloat(maxInput.value);
21901
+ if (isNaN(min) || isNaN(max)) {
21902
+ state.error = "Por favor, preencha ambos os valores.";
21903
+ renderModal3(container, state, modalId, onClose, onSave);
21904
+ return;
21905
+ }
21906
+ if (min >= max) {
21907
+ state.error = "A temperatura m\xEDnima deve ser menor que a m\xE1xima.";
21908
+ renderModal3(container, state, modalId, onClose, onSave);
21909
+ return;
21910
+ }
21911
+ if (min < 0 || max > 50) {
21912
+ state.error = "Os valores devem estar entre 0\xB0C e 50\xB0C.";
21913
+ renderModal3(container, state, modalId, onClose, onSave);
21914
+ return;
21915
+ }
21916
+ await onSave(min, max);
21917
+ });
21918
+ }
21919
+ function openTemperatureSettingsModal(params) {
21920
+ const modalId = `myio-temp-settings-${Date.now()}`;
21921
+ const state = {
21922
+ customerId: params.customerId,
21923
+ customerName: params.customerName || "",
21924
+ token: params.token,
21925
+ theme: params.theme || "dark",
21926
+ minTemperature: null,
21927
+ maxTemperature: null,
21928
+ isLoading: true,
21929
+ isSaving: false,
21930
+ error: null,
21931
+ successMessage: null
21932
+ };
21933
+ const container = document.createElement("div");
21934
+ container.id = `${modalId}-container`;
21935
+ document.body.appendChild(container);
21936
+ const destroy = () => {
21937
+ container.remove();
21938
+ params.onClose?.();
21939
+ };
21940
+ const handleSave = async (min, max) => {
21941
+ state.isSaving = true;
21942
+ state.error = null;
21943
+ state.successMessage = null;
21944
+ renderModal3(container, state, modalId, destroy, handleSave);
21945
+ try {
21946
+ await saveCustomerAttributes(state.customerId, state.token, min, max);
21947
+ state.minTemperature = min;
21948
+ state.maxTemperature = max;
21949
+ state.isSaving = false;
21950
+ state.successMessage = "Configura\xE7\xF5es salvas com sucesso!";
21951
+ renderModal3(container, state, modalId, destroy, handleSave);
21952
+ params.onSave?.({ minTemperature: min, maxTemperature: max });
21953
+ setTimeout(() => {
21954
+ destroy();
21955
+ }, 1500);
21956
+ } catch (error) {
21957
+ state.isSaving = false;
21958
+ state.error = `Erro ao salvar: ${error.message}`;
21959
+ renderModal3(container, state, modalId, destroy, handleSave);
21960
+ }
21961
+ };
21962
+ renderModal3(container, state, modalId, destroy, handleSave);
21963
+ fetchCustomerAttributes(state.customerId, state.token).then(({ minTemperature, maxTemperature }) => {
21964
+ state.minTemperature = minTemperature;
21965
+ state.maxTemperature = maxTemperature;
21966
+ state.isLoading = false;
21967
+ renderModal3(container, state, modalId, destroy, handleSave);
21968
+ }).catch((error) => {
21969
+ state.isLoading = false;
21970
+ state.error = `Erro ao carregar: ${error.message}`;
21971
+ renderModal3(container, state, modalId, destroy, handleSave);
21972
+ });
21973
+ return { destroy };
21974
+ }
21371
21975
  // Annotate the CommonJS export names for ESM import in node:
21372
21976
  0 && (module.exports = {
21373
21977
  CHART_COLORS,
@@ -21457,6 +22061,7 @@ function exportComparisonCSV(state) {
21457
22061
  openRealTimeTelemetryModal,
21458
22062
  openTemperatureComparisonModal,
21459
22063
  openTemperatureModal,
22064
+ openTemperatureSettingsModal,
21460
22065
  parseInputDateToDate,
21461
22066
  renderCardComponent,
21462
22067
  renderCardComponentEnhanced,