myio-js-library 0.1.200 → 0.1.202

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
@@ -583,6 +583,7 @@ __export(index_exports, {
583
583
  DEFAULT_GAS_GROUP_COLORS: () => DEFAULT_GAS_GROUP_COLORS,
584
584
  DEFAULT_SHOPPING_COLORS: () => DEFAULT_SHOPPING_COLORS,
585
585
  DEFAULT_WATER_GROUP_COLORS: () => DEFAULT_WATER_GROUP_COLORS,
586
+ DEVICE_COUNT_KEYS: () => DEVICE_COUNT_KEYS,
586
587
  DeviceComparisonTooltip: () => DeviceComparisonTooltip,
587
588
  DeviceStatusType: () => DeviceStatusType,
588
589
  EXPORT_DEFAULT_COLORS: () => EXPORT_DEFAULT_COLORS,
@@ -705,6 +706,7 @@ __export(index_exports, {
705
706
  myioExportData: () => myioExportData,
706
707
  normalizeRecipients: () => normalizeRecipients,
707
708
  numbers: () => numbers_exports,
709
+ openContractDevicesModal: () => openContractDevicesModal,
708
710
  openDashboardPopup: () => openDashboardPopup,
709
711
  openDashboardPopupAllReport: () => openDashboardPopupAllReport,
710
712
  openDashboardPopupEnergy: () => openDashboardPopupEnergy,
@@ -42155,6 +42157,965 @@ function createDistributionChartWidget(config) {
42155
42157
  };
42156
42158
  return instance;
42157
42159
  }
42160
+
42161
+ // src/components/premium-modals/contract-devices/types.ts
42162
+ var DEVICE_COUNT_KEYS = {
42163
+ energy: {
42164
+ total: "qtDevices3f",
42165
+ entries: "qtDevices3f-Entries",
42166
+ commonArea: "qtDevices3f-CommonArea",
42167
+ stores: "qtDevices3f-Stores"
42168
+ },
42169
+ water: {
42170
+ total: "qtDevicesHidr",
42171
+ entries: "qtDevicesHidr-Entries",
42172
+ commonArea: "qtDevicesHidr-CommonArea",
42173
+ stores: "qtDevicesHidr-Stores"
42174
+ },
42175
+ temperature: {
42176
+ total: "qtDevicesTemp",
42177
+ internal: "qtDevicesTemp-Internal",
42178
+ stores: "qtDevicesTemp-Stores"
42179
+ }
42180
+ };
42181
+
42182
+ // src/components/premium-modals/contract-devices/ContractDevicesModalView.ts
42183
+ var ContractDevicesModalView = class {
42184
+ container;
42185
+ modal;
42186
+ form;
42187
+ config;
42188
+ focusTrapElements = [];
42189
+ originalActiveElement = null;
42190
+ constructor(config) {
42191
+ this.config = config;
42192
+ this.createModal();
42193
+ }
42194
+ render(initialData) {
42195
+ this.originalActiveElement = document.activeElement;
42196
+ document.body.appendChild(this.container);
42197
+ this.populateForm(initialData);
42198
+ this.attachEventListeners();
42199
+ this.setupAccessibility();
42200
+ this.setupFocusTrap();
42201
+ }
42202
+ close() {
42203
+ this.teardownFocusTrap();
42204
+ if (this.originalActiveElement && "focus" in this.originalActiveElement) {
42205
+ this.originalActiveElement.focus();
42206
+ }
42207
+ if (this.container.parentNode) {
42208
+ this.container.parentNode.removeChild(this.container);
42209
+ }
42210
+ }
42211
+ showError(message) {
42212
+ const errorEl = this.modal.querySelector(".error-message");
42213
+ if (errorEl) {
42214
+ errorEl.textContent = message;
42215
+ errorEl.style.display = "block";
42216
+ errorEl.setAttribute("role", "alert");
42217
+ }
42218
+ }
42219
+ hideError() {
42220
+ const errorEl = this.modal.querySelector(".error-message");
42221
+ if (errorEl) {
42222
+ errorEl.style.display = "none";
42223
+ }
42224
+ }
42225
+ showLoadingState(isLoading) {
42226
+ const saveBtn = this.modal.querySelector(".btn-save");
42227
+ const cancelBtn = this.modal.querySelector(".btn-cancel");
42228
+ const formInputs = this.modal.querySelectorAll("input");
42229
+ if (saveBtn) {
42230
+ saveBtn.disabled = isLoading;
42231
+ saveBtn.textContent = isLoading ? "Salvando..." : "Salvar";
42232
+ }
42233
+ if (cancelBtn) {
42234
+ cancelBtn.disabled = isLoading;
42235
+ }
42236
+ formInputs.forEach((input) => {
42237
+ input.disabled = isLoading;
42238
+ });
42239
+ }
42240
+ getFormData() {
42241
+ const getValue = (name) => {
42242
+ const input = this.form.querySelector(`[name="${name}"]`);
42243
+ if (!input || input.value === "") return null;
42244
+ const num = parseInt(input.value, 10);
42245
+ return isNaN(num) ? null : num;
42246
+ };
42247
+ return {
42248
+ energy: {
42249
+ total: getValue("energy_total"),
42250
+ entries: getValue("energy_entries"),
42251
+ commonArea: getValue("energy_commonArea"),
42252
+ stores: getValue("energy_stores")
42253
+ },
42254
+ water: {
42255
+ total: getValue("water_total"),
42256
+ entries: getValue("water_entries"),
42257
+ commonArea: getValue("water_commonArea"),
42258
+ stores: getValue("water_stores")
42259
+ },
42260
+ temperature: {
42261
+ total: getValue("temperature_total"),
42262
+ internal: getValue("temperature_internal"),
42263
+ stores: getValue("temperature_stores")
42264
+ }
42265
+ };
42266
+ }
42267
+ createModal() {
42268
+ this.container = document.createElement("div");
42269
+ this.container.className = "myio-contract-devices-modal-overlay";
42270
+ this.container.innerHTML = this.getModalHTML();
42271
+ this.modal = this.container.querySelector(".myio-contract-devices-modal");
42272
+ this.form = this.modal.querySelector("form");
42273
+ }
42274
+ getModalHTML() {
42275
+ const width = typeof this.config.width === "number" ? `${this.config.width}px` : this.config.width;
42276
+ return `
42277
+ <div class="myio-contract-devices-modal-overlay" role="dialog" aria-modal="true" aria-labelledby="modal-title">
42278
+ <div class="myio-contract-devices-modal" style="width: ${width}">
42279
+ <div class="modal-header">
42280
+ <h3 id="modal-title">${this.config.title || "Configurar Dispositivos Contratados"}</h3>
42281
+ <button type="button" class="close-btn" aria-label="Fechar">&times;</button>
42282
+ </div>
42283
+ <div class="modal-body">
42284
+ <div class="error-message" style="display: none;" role="alert"></div>
42285
+ ${this.config.customerName ? `
42286
+ <div class="customer-info">
42287
+ <span class="customer-label">Shopping:</span>
42288
+ <span class="customer-name">${this.config.customerName}</span>
42289
+ </div>
42290
+ ` : ""}
42291
+ <form novalidate>
42292
+ ${this.getFormHTML()}
42293
+ </form>
42294
+ </div>
42295
+ <div class="modal-footer">
42296
+ <button type="button" class="btn-cancel">Fechar</button>
42297
+ <button type="button" class="btn-save btn-primary">Salvar</button>
42298
+ </div>
42299
+ </div>
42300
+ </div>
42301
+ ${this.getModalCSS()}
42302
+ `;
42303
+ }
42304
+ getFormHTML() {
42305
+ return `
42306
+ <div class="form-layout">
42307
+ <!-- Energy Section -->
42308
+ <div class="domain-card energy-card">
42309
+ <div class="domain-header">
42310
+ <span class="domain-icon">&#9889;</span>
42311
+ <h4>Energia</h4>
42312
+ </div>
42313
+ <div class="domain-fields">
42314
+ <div class="field-group">
42315
+ <label for="energy_total">Total Contratado</label>
42316
+ <input type="number" id="energy_total" name="energy_total" min="0" step="1" placeholder="0">
42317
+ <small class="field-key">${DEVICE_COUNT_KEYS.energy.total}</small>
42318
+ </div>
42319
+ <div class="field-group">
42320
+ <label for="energy_entries">Entradas</label>
42321
+ <input type="number" id="energy_entries" name="energy_entries" min="0" step="1" placeholder="0">
42322
+ <small class="field-key">${DEVICE_COUNT_KEYS.energy.entries}</small>
42323
+ </div>
42324
+ <div class="field-group">
42325
+ <label for="energy_commonArea">Area Comum</label>
42326
+ <input type="number" id="energy_commonArea" name="energy_commonArea" min="0" step="1" placeholder="0">
42327
+ <small class="field-key">${DEVICE_COUNT_KEYS.energy.commonArea}</small>
42328
+ </div>
42329
+ <div class="field-group">
42330
+ <label for="energy_stores">Lojas</label>
42331
+ <input type="number" id="energy_stores" name="energy_stores" min="0" step="1" placeholder="0">
42332
+ <small class="field-key">${DEVICE_COUNT_KEYS.energy.stores}</small>
42333
+ </div>
42334
+ </div>
42335
+ </div>
42336
+
42337
+ <!-- Water Section -->
42338
+ <div class="domain-card water-card">
42339
+ <div class="domain-header">
42340
+ <span class="domain-icon">&#128167;</span>
42341
+ <h4>Agua</h4>
42342
+ </div>
42343
+ <div class="domain-fields">
42344
+ <div class="field-group">
42345
+ <label for="water_total">Total Contratado</label>
42346
+ <input type="number" id="water_total" name="water_total" min="0" step="1" placeholder="0">
42347
+ <small class="field-key">${DEVICE_COUNT_KEYS.water.total}</small>
42348
+ </div>
42349
+ <div class="field-group">
42350
+ <label for="water_entries">Entradas</label>
42351
+ <input type="number" id="water_entries" name="water_entries" min="0" step="1" placeholder="0">
42352
+ <small class="field-key">${DEVICE_COUNT_KEYS.water.entries}</small>
42353
+ </div>
42354
+ <div class="field-group">
42355
+ <label for="water_commonArea">Area Comum</label>
42356
+ <input type="number" id="water_commonArea" name="water_commonArea" min="0" step="1" placeholder="0">
42357
+ <small class="field-key">${DEVICE_COUNT_KEYS.water.commonArea}</small>
42358
+ </div>
42359
+ <div class="field-group">
42360
+ <label for="water_stores">Lojas</label>
42361
+ <input type="number" id="water_stores" name="water_stores" min="0" step="1" placeholder="0">
42362
+ <small class="field-key">${DEVICE_COUNT_KEYS.water.stores}</small>
42363
+ </div>
42364
+ </div>
42365
+ </div>
42366
+
42367
+ <!-- Temperature Section -->
42368
+ <div class="domain-card temperature-card">
42369
+ <div class="domain-header">
42370
+ <span class="domain-icon">&#127777;</span>
42371
+ <h4>Temperatura</h4>
42372
+ </div>
42373
+ <div class="domain-fields">
42374
+ <div class="field-group">
42375
+ <label for="temperature_total">Total Contratado</label>
42376
+ <input type="number" id="temperature_total" name="temperature_total" min="0" step="1" placeholder="0">
42377
+ <small class="field-key">${DEVICE_COUNT_KEYS.temperature.total}</small>
42378
+ </div>
42379
+ <div class="field-group">
42380
+ <label for="temperature_internal">Sensores Internos</label>
42381
+ <input type="number" id="temperature_internal" name="temperature_internal" min="0" step="1" placeholder="0">
42382
+ <small class="field-key">${DEVICE_COUNT_KEYS.temperature.internal}</small>
42383
+ </div>
42384
+ <div class="field-group">
42385
+ <label for="temperature_stores">Lojas</label>
42386
+ <input type="number" id="temperature_stores" name="temperature_stores" min="0" step="1" placeholder="0">
42387
+ <small class="field-key">${DEVICE_COUNT_KEYS.temperature.stores}</small>
42388
+ </div>
42389
+ </div>
42390
+ </div>
42391
+ </div>
42392
+ `;
42393
+ }
42394
+ getModalCSS() {
42395
+ return `
42396
+ <style>
42397
+ .myio-contract-devices-modal-overlay {
42398
+ position: fixed;
42399
+ top: 0;
42400
+ left: 0;
42401
+ right: 0;
42402
+ bottom: 0;
42403
+ background: rgba(0, 0, 0, 0.5);
42404
+ display: flex;
42405
+ align-items: center;
42406
+ justify-content: center;
42407
+ z-index: 10000;
42408
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
42409
+ }
42410
+
42411
+ .myio-contract-devices-modal {
42412
+ background: white;
42413
+ border-radius: 12px;
42414
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.25);
42415
+ max-width: 95vw;
42416
+ max-height: 90vh;
42417
+ width: 800px;
42418
+ overflow: hidden;
42419
+ display: flex;
42420
+ flex-direction: column;
42421
+ }
42422
+
42423
+ .myio-contract-devices-modal .modal-header {
42424
+ background: linear-gradient(135deg, #3e1a7d 0%, #5c2d91 100%);
42425
+ color: white;
42426
+ padding: 20px 24px;
42427
+ display: flex;
42428
+ justify-content: space-between;
42429
+ align-items: center;
42430
+ }
42431
+
42432
+ .myio-contract-devices-modal .modal-header h3 {
42433
+ margin: 0;
42434
+ font-size: 18px;
42435
+ font-weight: 600;
42436
+ color: white;
42437
+ }
42438
+
42439
+ .myio-contract-devices-modal .close-btn {
42440
+ background: none;
42441
+ border: none;
42442
+ font-size: 24px;
42443
+ cursor: pointer;
42444
+ color: white;
42445
+ padding: 0;
42446
+ width: 32px;
42447
+ height: 32px;
42448
+ display: flex;
42449
+ align-items: center;
42450
+ justify-content: center;
42451
+ border-radius: 4px;
42452
+ transition: background 0.2s;
42453
+ }
42454
+
42455
+ .myio-contract-devices-modal .close-btn:hover {
42456
+ background: rgba(255, 255, 255, 0.1);
42457
+ }
42458
+
42459
+ .myio-contract-devices-modal .modal-body {
42460
+ padding: 24px;
42461
+ overflow-y: auto;
42462
+ flex: 1;
42463
+ background: #f8f9fa;
42464
+ }
42465
+
42466
+ .myio-contract-devices-modal .error-message {
42467
+ background: #fee;
42468
+ border: 1px solid #fcc;
42469
+ color: #c33;
42470
+ padding: 12px;
42471
+ border-radius: 6px;
42472
+ margin-bottom: 16px;
42473
+ font-size: 14px;
42474
+ white-space: pre-line;
42475
+ line-height: 1.6;
42476
+ }
42477
+
42478
+ .myio-contract-devices-modal .customer-info {
42479
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
42480
+ padding: 16px 20px;
42481
+ border-radius: 8px;
42482
+ margin-bottom: 20px;
42483
+ display: flex;
42484
+ align-items: center;
42485
+ gap: 10px;
42486
+ }
42487
+
42488
+ .myio-contract-devices-modal .customer-label {
42489
+ color: rgba(255, 255, 255, 0.8);
42490
+ font-size: 13px;
42491
+ font-weight: 500;
42492
+ }
42493
+
42494
+ .myio-contract-devices-modal .customer-name {
42495
+ color: white;
42496
+ font-size: 16px;
42497
+ font-weight: 600;
42498
+ }
42499
+
42500
+ .myio-contract-devices-modal .form-layout {
42501
+ display: grid;
42502
+ grid-template-columns: repeat(3, 1fr);
42503
+ gap: 20px;
42504
+ }
42505
+
42506
+ .myio-contract-devices-modal .domain-card {
42507
+ background: white;
42508
+ border-radius: 10px;
42509
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
42510
+ overflow: hidden;
42511
+ }
42512
+
42513
+ .myio-contract-devices-modal .domain-header {
42514
+ padding: 14px 16px;
42515
+ display: flex;
42516
+ align-items: center;
42517
+ gap: 10px;
42518
+ border-bottom: 1px solid #eee;
42519
+ }
42520
+
42521
+ .myio-contract-devices-modal .domain-header h4 {
42522
+ margin: 0;
42523
+ font-size: 15px;
42524
+ font-weight: 600;
42525
+ color: #333;
42526
+ }
42527
+
42528
+ .myio-contract-devices-modal .domain-icon {
42529
+ font-size: 20px;
42530
+ }
42531
+
42532
+ .myio-contract-devices-modal .energy-card .domain-header {
42533
+ background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
42534
+ }
42535
+
42536
+ .myio-contract-devices-modal .water-card .domain-header {
42537
+ background: linear-gradient(135deg, #dbeafe 0%, #93c5fd 100%);
42538
+ }
42539
+
42540
+ .myio-contract-devices-modal .temperature-card .domain-header {
42541
+ background: linear-gradient(135deg, #fce7f3 0%, #f9a8d4 100%);
42542
+ }
42543
+
42544
+ .myio-contract-devices-modal .domain-fields {
42545
+ padding: 16px;
42546
+ display: flex;
42547
+ flex-direction: column;
42548
+ gap: 14px;
42549
+ }
42550
+
42551
+ .myio-contract-devices-modal .field-group {
42552
+ display: flex;
42553
+ flex-direction: column;
42554
+ gap: 4px;
42555
+ }
42556
+
42557
+ .myio-contract-devices-modal .field-group label {
42558
+ font-size: 13px;
42559
+ font-weight: 500;
42560
+ color: #555;
42561
+ }
42562
+
42563
+ .myio-contract-devices-modal .field-group input {
42564
+ width: 100%;
42565
+ padding: 10px 12px;
42566
+ border: 1px solid #ddd;
42567
+ border-radius: 6px;
42568
+ font-size: 14px;
42569
+ transition: border-color 0.2s, box-shadow 0.2s;
42570
+ box-sizing: border-box;
42571
+ }
42572
+
42573
+ .myio-contract-devices-modal .field-group input:focus {
42574
+ outline: none;
42575
+ border-color: #3e1a7d;
42576
+ box-shadow: 0 0 0 3px rgba(62, 26, 125, 0.15);
42577
+ }
42578
+
42579
+ .myio-contract-devices-modal .field-key {
42580
+ font-size: 10px;
42581
+ color: #999;
42582
+ font-family: 'Courier New', monospace;
42583
+ }
42584
+
42585
+ .myio-contract-devices-modal .modal-footer {
42586
+ padding: 16px 24px;
42587
+ border-top: 1px solid #e0e0e0;
42588
+ display: flex;
42589
+ justify-content: flex-end;
42590
+ gap: 12px;
42591
+ background: white;
42592
+ }
42593
+
42594
+ .myio-contract-devices-modal .modal-footer button {
42595
+ padding: 10px 24px;
42596
+ border: none;
42597
+ border-radius: 6px;
42598
+ font-size: 14px;
42599
+ font-weight: 500;
42600
+ cursor: pointer;
42601
+ transition: all 0.2s;
42602
+ }
42603
+
42604
+ .myio-contract-devices-modal .btn-cancel {
42605
+ background: #6c757d;
42606
+ color: white;
42607
+ }
42608
+
42609
+ .myio-contract-devices-modal .btn-cancel:hover:not(:disabled) {
42610
+ background: #545b62;
42611
+ }
42612
+
42613
+ .myio-contract-devices-modal .btn-primary {
42614
+ background: #3e1a7d;
42615
+ color: white;
42616
+ }
42617
+
42618
+ .myio-contract-devices-modal .btn-primary:hover:not(:disabled) {
42619
+ background: #2d1458;
42620
+ }
42621
+
42622
+ .myio-contract-devices-modal .modal-footer button:disabled {
42623
+ opacity: 0.6;
42624
+ cursor: not-allowed;
42625
+ }
42626
+
42627
+ /* Responsive */
42628
+ @media (max-width: 900px) {
42629
+ .myio-contract-devices-modal .form-layout {
42630
+ grid-template-columns: 1fr;
42631
+ }
42632
+
42633
+ .myio-contract-devices-modal {
42634
+ width: 95vw !important;
42635
+ }
42636
+ }
42637
+
42638
+ /* Scrollbar */
42639
+ .myio-contract-devices-modal .modal-body::-webkit-scrollbar {
42640
+ width: 6px;
42641
+ }
42642
+
42643
+ .myio-contract-devices-modal .modal-body::-webkit-scrollbar-track {
42644
+ background: #f1f1f1;
42645
+ border-radius: 3px;
42646
+ }
42647
+
42648
+ .myio-contract-devices-modal .modal-body::-webkit-scrollbar-thumb {
42649
+ background: #c1c1c1;
42650
+ border-radius: 3px;
42651
+ }
42652
+ </style>
42653
+ `;
42654
+ }
42655
+ populateForm(data) {
42656
+ const setValue = (name, value) => {
42657
+ const input = this.form.querySelector(`[name="${name}"]`);
42658
+ if (input && value !== null && value !== void 0) {
42659
+ input.value = String(value);
42660
+ }
42661
+ };
42662
+ if (data.energy) {
42663
+ setValue("energy_total", data.energy.total);
42664
+ setValue("energy_entries", data.energy.entries);
42665
+ setValue("energy_commonArea", data.energy.commonArea);
42666
+ setValue("energy_stores", data.energy.stores);
42667
+ }
42668
+ if (data.water) {
42669
+ setValue("water_total", data.water.total);
42670
+ setValue("water_entries", data.water.entries);
42671
+ setValue("water_commonArea", data.water.commonArea);
42672
+ setValue("water_stores", data.water.stores);
42673
+ }
42674
+ if (data.temperature) {
42675
+ setValue("temperature_total", data.temperature.total);
42676
+ setValue("temperature_internal", data.temperature.internal);
42677
+ setValue("temperature_stores", data.temperature.stores);
42678
+ }
42679
+ }
42680
+ attachEventListeners() {
42681
+ const closeBtn = this.modal.querySelector(".close-btn");
42682
+ if (closeBtn) {
42683
+ closeBtn.addEventListener("click", (e) => {
42684
+ e.preventDefault();
42685
+ this.config.onClose();
42686
+ });
42687
+ }
42688
+ const cancelBtn = this.modal.querySelector(".btn-cancel");
42689
+ if (cancelBtn) {
42690
+ cancelBtn.addEventListener("click", (e) => {
42691
+ e.preventDefault();
42692
+ this.config.onClose();
42693
+ });
42694
+ }
42695
+ const saveBtn = this.modal.querySelector(".btn-save");
42696
+ if (saveBtn) {
42697
+ saveBtn.addEventListener("click", async (e) => {
42698
+ e.preventDefault();
42699
+ this.hideError();
42700
+ const formData = this.getFormData();
42701
+ await this.config.onSave(formData);
42702
+ });
42703
+ }
42704
+ this.container.addEventListener("click", (e) => {
42705
+ const target = e.target;
42706
+ if (target.classList.contains("myio-contract-devices-modal-overlay") && this.config.closeOnBackdrop !== false) {
42707
+ this.config.onClose();
42708
+ }
42709
+ });
42710
+ }
42711
+ setupAccessibility() {
42712
+ const firstInput = this.modal.querySelector("input");
42713
+ if (firstInput) {
42714
+ setTimeout(() => firstInput.focus(), 100);
42715
+ }
42716
+ this.modal.setAttribute("aria-labelledby", "modal-title");
42717
+ }
42718
+ setupFocusTrap() {
42719
+ this.focusTrapElements = Array.from(
42720
+ this.modal.querySelectorAll('button, input, [tabindex]:not([tabindex="-1"])')
42721
+ );
42722
+ this.modal.addEventListener("keydown", this.handleKeyDown.bind(this));
42723
+ }
42724
+ teardownFocusTrap() {
42725
+ this.modal.removeEventListener("keydown", this.handleKeyDown.bind(this));
42726
+ }
42727
+ handleKeyDown(event) {
42728
+ if (event.key === "Escape" && this.config.closeOnBackdrop !== false) {
42729
+ event.preventDefault();
42730
+ this.config.onClose();
42731
+ return;
42732
+ }
42733
+ if (event.key === "Tab") {
42734
+ const firstElement = this.focusTrapElements[0];
42735
+ const lastElement = this.focusTrapElements[this.focusTrapElements.length - 1];
42736
+ if (event.shiftKey) {
42737
+ if (document.activeElement === firstElement) {
42738
+ event.preventDefault();
42739
+ lastElement.focus();
42740
+ }
42741
+ } else {
42742
+ if (document.activeElement === lastElement) {
42743
+ event.preventDefault();
42744
+ firstElement.focus();
42745
+ }
42746
+ }
42747
+ }
42748
+ }
42749
+ };
42750
+
42751
+ // src/components/premium-modals/contract-devices/ContractDevicesPersister.ts
42752
+ var DefaultContractDevicesPersister = class {
42753
+ jwtToken;
42754
+ tbBaseUrl;
42755
+ constructor(jwtToken, apiConfig) {
42756
+ this.jwtToken = jwtToken;
42757
+ this.tbBaseUrl = apiConfig?.tbBaseUrl || window.location.origin;
42758
+ }
42759
+ async saveDeviceCounts(customerId, counts) {
42760
+ try {
42761
+ const payload = {};
42762
+ if (counts.energy.total !== null) {
42763
+ payload[DEVICE_COUNT_KEYS.energy.total] = counts.energy.total;
42764
+ }
42765
+ if (counts.energy.entries !== null) {
42766
+ payload[DEVICE_COUNT_KEYS.energy.entries] = counts.energy.entries;
42767
+ }
42768
+ if (counts.energy.commonArea !== null) {
42769
+ payload[DEVICE_COUNT_KEYS.energy.commonArea] = counts.energy.commonArea;
42770
+ }
42771
+ if (counts.energy.stores !== null) {
42772
+ payload[DEVICE_COUNT_KEYS.energy.stores] = counts.energy.stores;
42773
+ }
42774
+ if (counts.water.total !== null) {
42775
+ payload[DEVICE_COUNT_KEYS.water.total] = counts.water.total;
42776
+ }
42777
+ if (counts.water.entries !== null) {
42778
+ payload[DEVICE_COUNT_KEYS.water.entries] = counts.water.entries;
42779
+ }
42780
+ if (counts.water.commonArea !== null) {
42781
+ payload[DEVICE_COUNT_KEYS.water.commonArea] = counts.water.commonArea;
42782
+ }
42783
+ if (counts.water.stores !== null) {
42784
+ payload[DEVICE_COUNT_KEYS.water.stores] = counts.water.stores;
42785
+ }
42786
+ if (counts.temperature.total !== null) {
42787
+ payload[DEVICE_COUNT_KEYS.temperature.total] = counts.temperature.total;
42788
+ }
42789
+ if (counts.temperature.internal !== null) {
42790
+ payload[DEVICE_COUNT_KEYS.temperature.internal] = counts.temperature.internal;
42791
+ }
42792
+ if (counts.temperature.stores !== null) {
42793
+ payload[DEVICE_COUNT_KEYS.temperature.stores] = counts.temperature.stores;
42794
+ }
42795
+ console.log("[ContractDevicesPersister] Saving to CUSTOMER SERVER_SCOPE:", payload);
42796
+ const res = await fetch(
42797
+ `${this.tbBaseUrl}/api/plugins/telemetry/CUSTOMER/${customerId}/attributes/SERVER_SCOPE`,
42798
+ {
42799
+ method: "POST",
42800
+ headers: {
42801
+ "X-Authorization": `Bearer ${this.jwtToken}`,
42802
+ "Content-Type": "application/json"
42803
+ },
42804
+ body: JSON.stringify(payload)
42805
+ }
42806
+ );
42807
+ if (!res.ok) {
42808
+ throw this.createHttpError(res.status, await res.text().catch(() => ""));
42809
+ }
42810
+ return {
42811
+ ok: true,
42812
+ updatedKeys: Object.keys(payload),
42813
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
42814
+ };
42815
+ } catch (error) {
42816
+ console.error("[ContractDevicesPersister] Save failed:", error);
42817
+ return {
42818
+ ok: false,
42819
+ error: this.mapError(error)
42820
+ };
42821
+ }
42822
+ }
42823
+ createHttpError(status, body) {
42824
+ const error = new Error(`HTTP ${status}: ${body}`);
42825
+ error.status = status;
42826
+ error.body = body;
42827
+ return error;
42828
+ }
42829
+ mapError(error) {
42830
+ const status = error.status;
42831
+ if (status === 400) {
42832
+ return {
42833
+ code: "VALIDATION_ERROR",
42834
+ message: "Dados invalidos",
42835
+ userAction: "FIX_INPUT",
42836
+ cause: error
42837
+ };
42838
+ }
42839
+ if (status === 401) {
42840
+ return {
42841
+ code: "TOKEN_EXPIRED",
42842
+ message: "Token de autenticacao expirado",
42843
+ userAction: "RE_AUTH",
42844
+ cause: error
42845
+ };
42846
+ }
42847
+ if (status === 403) {
42848
+ return {
42849
+ code: "AUTH_ERROR",
42850
+ message: "Permissao insuficiente",
42851
+ userAction: "RE_AUTH",
42852
+ cause: error
42853
+ };
42854
+ }
42855
+ if (status === 404) {
42856
+ return {
42857
+ code: "NETWORK_ERROR",
42858
+ message: "Cliente nao encontrado",
42859
+ userAction: "CONTACT_ADMIN",
42860
+ cause: error
42861
+ };
42862
+ }
42863
+ if (status >= 500) {
42864
+ return {
42865
+ code: "NETWORK_ERROR",
42866
+ message: "Erro no servidor",
42867
+ userAction: "RETRY",
42868
+ cause: error
42869
+ };
42870
+ }
42871
+ return {
42872
+ code: "UNKNOWN_ERROR",
42873
+ message: error.message || "Erro desconhecido",
42874
+ userAction: "CONTACT_ADMIN",
42875
+ cause: error
42876
+ };
42877
+ }
42878
+ };
42879
+
42880
+ // src/components/premium-modals/contract-devices/ContractDevicesFetcher.ts
42881
+ var DefaultContractDevicesFetcher = class {
42882
+ jwtToken;
42883
+ tbBaseUrl;
42884
+ constructor(jwtToken, apiConfig) {
42885
+ this.jwtToken = jwtToken;
42886
+ this.tbBaseUrl = apiConfig?.tbBaseUrl || window.location.origin;
42887
+ }
42888
+ async fetchCurrentCounts(customerId) {
42889
+ try {
42890
+ const keys = [
42891
+ DEVICE_COUNT_KEYS.energy.total,
42892
+ DEVICE_COUNT_KEYS.energy.entries,
42893
+ DEVICE_COUNT_KEYS.energy.commonArea,
42894
+ DEVICE_COUNT_KEYS.energy.stores,
42895
+ DEVICE_COUNT_KEYS.water.total,
42896
+ DEVICE_COUNT_KEYS.water.entries,
42897
+ DEVICE_COUNT_KEYS.water.commonArea,
42898
+ DEVICE_COUNT_KEYS.water.stores,
42899
+ DEVICE_COUNT_KEYS.temperature.total,
42900
+ DEVICE_COUNT_KEYS.temperature.internal,
42901
+ DEVICE_COUNT_KEYS.temperature.stores
42902
+ ];
42903
+ const url = `${this.tbBaseUrl}/api/plugins/telemetry/CUSTOMER/${customerId}/values/attributes/SERVER_SCOPE?keys=${keys.join(",")}`;
42904
+ console.log("[ContractDevicesFetcher] Fetching from:", url);
42905
+ const res = await fetch(url, {
42906
+ headers: {
42907
+ "X-Authorization": `Bearer ${this.jwtToken}`,
42908
+ "Content-Type": "application/json"
42909
+ }
42910
+ });
42911
+ if (!res.ok) {
42912
+ console.warn("[ContractDevicesFetcher] Fetch failed:", res.status);
42913
+ return {};
42914
+ }
42915
+ const data = await res.json();
42916
+ console.log("[ContractDevicesFetcher] Received data:", data);
42917
+ return this.parseAttributesToCounts(data);
42918
+ } catch (error) {
42919
+ console.error("[ContractDevicesFetcher] Error fetching counts:", error);
42920
+ return {};
42921
+ }
42922
+ }
42923
+ parseAttributesToCounts(attributes) {
42924
+ const getValue = (key) => {
42925
+ const attr = attributes.find((a) => a.key === key);
42926
+ if (!attr) return null;
42927
+ const num = parseInt(attr.value, 10);
42928
+ return isNaN(num) ? null : num;
42929
+ };
42930
+ return {
42931
+ energy: {
42932
+ total: getValue(DEVICE_COUNT_KEYS.energy.total),
42933
+ entries: getValue(DEVICE_COUNT_KEYS.energy.entries),
42934
+ commonArea: getValue(DEVICE_COUNT_KEYS.energy.commonArea),
42935
+ stores: getValue(DEVICE_COUNT_KEYS.energy.stores)
42936
+ },
42937
+ water: {
42938
+ total: getValue(DEVICE_COUNT_KEYS.water.total),
42939
+ entries: getValue(DEVICE_COUNT_KEYS.water.entries),
42940
+ commonArea: getValue(DEVICE_COUNT_KEYS.water.commonArea),
42941
+ stores: getValue(DEVICE_COUNT_KEYS.water.stores)
42942
+ },
42943
+ temperature: {
42944
+ total: getValue(DEVICE_COUNT_KEYS.temperature.total),
42945
+ internal: getValue(DEVICE_COUNT_KEYS.temperature.internal),
42946
+ stores: getValue(DEVICE_COUNT_KEYS.temperature.stores)
42947
+ }
42948
+ };
42949
+ }
42950
+ };
42951
+
42952
+ // src/components/premium-modals/contract-devices/ContractDevicesController.ts
42953
+ var ContractDevicesController = class {
42954
+ params;
42955
+ view = null;
42956
+ persister;
42957
+ fetcher;
42958
+ constructor(params) {
42959
+ this.params = params;
42960
+ this.persister = new DefaultContractDevicesPersister(
42961
+ params.jwtToken,
42962
+ params.api
42963
+ );
42964
+ this.fetcher = new DefaultContractDevicesFetcher(
42965
+ params.jwtToken,
42966
+ params.api
42967
+ );
42968
+ }
42969
+ async show() {
42970
+ let seedData = this.params.seed || {};
42971
+ try {
42972
+ const existingCounts = await this.fetcher.fetchCurrentCounts(this.params.customerId);
42973
+ seedData = this.mergeCounts(seedData, existingCounts);
42974
+ console.log("[ContractDevicesController] Merged seed data:", seedData);
42975
+ } catch (error) {
42976
+ console.warn("[ContractDevicesController] Failed to fetch existing counts:", error);
42977
+ }
42978
+ const viewConfig = {
42979
+ title: this.params.ui?.title || "Configurar Dispositivos Contratados",
42980
+ width: this.params.ui?.width || 800,
42981
+ closeOnBackdrop: this.params.ui?.closeOnBackdrop !== false,
42982
+ customerName: this.params.customerName,
42983
+ onSave: this.handleSave.bind(this),
42984
+ onClose: this.handleClose.bind(this)
42985
+ };
42986
+ this.view = new ContractDevicesModalView(viewConfig);
42987
+ this.view.render(seedData);
42988
+ }
42989
+ async handleSave(formData) {
42990
+ if (!this.view) return;
42991
+ const validationError = this.validateTotals(formData);
42992
+ if (validationError) {
42993
+ this.view.showError(validationError);
42994
+ return;
42995
+ }
42996
+ this.view.showLoadingState(true);
42997
+ this.view.hideError();
42998
+ try {
42999
+ const result = await this.persister.saveDeviceCounts(
43000
+ this.params.customerId,
43001
+ formData
43002
+ );
43003
+ if (result.ok) {
43004
+ console.log("[ContractDevicesController] Save successful:", result);
43005
+ if (this.params.onSaved) {
43006
+ this.params.onSaved(result);
43007
+ }
43008
+ this.handleClose();
43009
+ } else {
43010
+ console.error("[ContractDevicesController] Save failed:", result.error);
43011
+ this.view.showError(result.error?.message || "Erro ao salvar configuracoes");
43012
+ if (this.params.onError && result.error) {
43013
+ this.params.onError(result.error);
43014
+ }
43015
+ }
43016
+ } catch (error) {
43017
+ console.error("[ContractDevicesController] Unexpected error:", error);
43018
+ this.view.showError(error.message || "Erro inesperado");
43019
+ if (this.params.onError) {
43020
+ this.params.onError({
43021
+ code: "UNKNOWN_ERROR",
43022
+ message: error.message || "Erro desconhecido",
43023
+ cause: error
43024
+ });
43025
+ }
43026
+ } finally {
43027
+ if (this.view) {
43028
+ this.view.showLoadingState(false);
43029
+ }
43030
+ }
43031
+ }
43032
+ handleClose() {
43033
+ if (this.view) {
43034
+ this.view.close();
43035
+ this.view = null;
43036
+ }
43037
+ if (this.params.onClose) {
43038
+ this.params.onClose();
43039
+ }
43040
+ }
43041
+ /**
43042
+ * Validate that totals match sum of components for each domain
43043
+ * Returns error message if validation fails, null if valid
43044
+ */
43045
+ validateTotals(formData) {
43046
+ const errors = [];
43047
+ if (formData.energy.total !== null) {
43048
+ const energySum = (formData.energy.entries || 0) + (formData.energy.commonArea || 0) + (formData.energy.stores || 0);
43049
+ if (formData.energy.total !== energySum) {
43050
+ errors.push(`Energia: Total (${formData.energy.total}) deve ser igual a Entradas + Area Comum + Lojas (${energySum})`);
43051
+ }
43052
+ }
43053
+ if (formData.water.total !== null) {
43054
+ const waterSum = (formData.water.entries || 0) + (formData.water.commonArea || 0) + (formData.water.stores || 0);
43055
+ if (formData.water.total !== waterSum) {
43056
+ errors.push(`Agua: Total (${formData.water.total}) deve ser igual a Entradas + Area Comum + Lojas (${waterSum})`);
43057
+ }
43058
+ }
43059
+ if (formData.temperature.total !== null) {
43060
+ const tempSum = (formData.temperature.internal || 0) + (formData.temperature.stores || 0);
43061
+ if (formData.temperature.total !== tempSum) {
43062
+ errors.push(`Temperatura: Total (${formData.temperature.total}) deve ser igual a Sensores Internos + Lojas (${tempSum})`);
43063
+ }
43064
+ }
43065
+ return errors.length > 0 ? errors.join("\n") : null;
43066
+ }
43067
+ mergeCounts(seed, fetched) {
43068
+ return {
43069
+ energy: {
43070
+ total: fetched.energy?.total ?? seed.energy?.total ?? null,
43071
+ entries: fetched.energy?.entries ?? seed.energy?.entries ?? null,
43072
+ commonArea: fetched.energy?.commonArea ?? seed.energy?.commonArea ?? null,
43073
+ stores: fetched.energy?.stores ?? seed.energy?.stores ?? null
43074
+ },
43075
+ water: {
43076
+ total: fetched.water?.total ?? seed.water?.total ?? null,
43077
+ entries: fetched.water?.entries ?? seed.water?.entries ?? null,
43078
+ commonArea: fetched.water?.commonArea ?? seed.water?.commonArea ?? null,
43079
+ stores: fetched.water?.stores ?? seed.water?.stores ?? null
43080
+ },
43081
+ temperature: {
43082
+ total: fetched.temperature?.total ?? seed.temperature?.total ?? null,
43083
+ internal: fetched.temperature?.internal ?? seed.temperature?.internal ?? null,
43084
+ stores: fetched.temperature?.stores ?? seed.temperature?.stores ?? null
43085
+ }
43086
+ };
43087
+ }
43088
+ };
43089
+
43090
+ // src/components/premium-modals/contract-devices/openContractDevicesModal.ts
43091
+ async function openContractDevicesModal(params) {
43092
+ if (!params.jwtToken) {
43093
+ throw new Error("jwtToken is required for contract devices persistence");
43094
+ }
43095
+ if (!params.customerId) {
43096
+ throw new Error("customerId is required");
43097
+ }
43098
+ console.info("[openContractDevicesModal] Initializing contract devices modal", {
43099
+ customerId: params.customerId,
43100
+ customerName: params.customerName,
43101
+ hasJwtToken: !!params.jwtToken,
43102
+ hasSeedData: !!params.seed
43103
+ });
43104
+ const controller = new ContractDevicesController(params);
43105
+ try {
43106
+ await controller.show();
43107
+ } catch (error) {
43108
+ console.error("[openContractDevicesModal] Error:", error);
43109
+ if (params.onError) {
43110
+ params.onError({
43111
+ code: "UNKNOWN_ERROR",
43112
+ message: error.message || "Erro ao abrir modal de dispositivos contratados",
43113
+ cause: error
43114
+ });
43115
+ }
43116
+ throw error;
43117
+ }
43118
+ }
42158
43119
  // Annotate the CommonJS export names for ESM import in node:
42159
43120
  0 && (module.exports = {
42160
43121
  ANNOTATION_TYPE_COLORS,
@@ -42172,6 +43133,7 @@ function createDistributionChartWidget(config) {
42172
43133
  DEFAULT_GAS_GROUP_COLORS,
42173
43134
  DEFAULT_SHOPPING_COLORS,
42174
43135
  DEFAULT_WATER_GROUP_COLORS,
43136
+ DEVICE_COUNT_KEYS,
42175
43137
  DeviceComparisonTooltip,
42176
43138
  DeviceStatusType,
42177
43139
  EXPORT_DEFAULT_COLORS,
@@ -42294,6 +43256,7 @@ function createDistributionChartWidget(config) {
42294
43256
  myioExportData,
42295
43257
  normalizeRecipients,
42296
43258
  numbers,
43259
+ openContractDevicesModal,
42297
43260
  openDashboardPopup,
42298
43261
  openDashboardPopupAllReport,
42299
43262
  openDashboardPopupEnergy,