myio-js-library 0.1.199 → 0.1.201

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,932 @@ 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
+ }
42475
+
42476
+ .myio-contract-devices-modal .customer-info {
42477
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
42478
+ padding: 16px 20px;
42479
+ border-radius: 8px;
42480
+ margin-bottom: 20px;
42481
+ display: flex;
42482
+ align-items: center;
42483
+ gap: 10px;
42484
+ }
42485
+
42486
+ .myio-contract-devices-modal .customer-label {
42487
+ color: rgba(255, 255, 255, 0.8);
42488
+ font-size: 13px;
42489
+ font-weight: 500;
42490
+ }
42491
+
42492
+ .myio-contract-devices-modal .customer-name {
42493
+ color: white;
42494
+ font-size: 16px;
42495
+ font-weight: 600;
42496
+ }
42497
+
42498
+ .myio-contract-devices-modal .form-layout {
42499
+ display: grid;
42500
+ grid-template-columns: repeat(3, 1fr);
42501
+ gap: 20px;
42502
+ }
42503
+
42504
+ .myio-contract-devices-modal .domain-card {
42505
+ background: white;
42506
+ border-radius: 10px;
42507
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
42508
+ overflow: hidden;
42509
+ }
42510
+
42511
+ .myio-contract-devices-modal .domain-header {
42512
+ padding: 14px 16px;
42513
+ display: flex;
42514
+ align-items: center;
42515
+ gap: 10px;
42516
+ border-bottom: 1px solid #eee;
42517
+ }
42518
+
42519
+ .myio-contract-devices-modal .domain-header h4 {
42520
+ margin: 0;
42521
+ font-size: 15px;
42522
+ font-weight: 600;
42523
+ color: #333;
42524
+ }
42525
+
42526
+ .myio-contract-devices-modal .domain-icon {
42527
+ font-size: 20px;
42528
+ }
42529
+
42530
+ .myio-contract-devices-modal .energy-card .domain-header {
42531
+ background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
42532
+ }
42533
+
42534
+ .myio-contract-devices-modal .water-card .domain-header {
42535
+ background: linear-gradient(135deg, #dbeafe 0%, #93c5fd 100%);
42536
+ }
42537
+
42538
+ .myio-contract-devices-modal .temperature-card .domain-header {
42539
+ background: linear-gradient(135deg, #fce7f3 0%, #f9a8d4 100%);
42540
+ }
42541
+
42542
+ .myio-contract-devices-modal .domain-fields {
42543
+ padding: 16px;
42544
+ display: flex;
42545
+ flex-direction: column;
42546
+ gap: 14px;
42547
+ }
42548
+
42549
+ .myio-contract-devices-modal .field-group {
42550
+ display: flex;
42551
+ flex-direction: column;
42552
+ gap: 4px;
42553
+ }
42554
+
42555
+ .myio-contract-devices-modal .field-group label {
42556
+ font-size: 13px;
42557
+ font-weight: 500;
42558
+ color: #555;
42559
+ }
42560
+
42561
+ .myio-contract-devices-modal .field-group input {
42562
+ width: 100%;
42563
+ padding: 10px 12px;
42564
+ border: 1px solid #ddd;
42565
+ border-radius: 6px;
42566
+ font-size: 14px;
42567
+ transition: border-color 0.2s, box-shadow 0.2s;
42568
+ box-sizing: border-box;
42569
+ }
42570
+
42571
+ .myio-contract-devices-modal .field-group input:focus {
42572
+ outline: none;
42573
+ border-color: #3e1a7d;
42574
+ box-shadow: 0 0 0 3px rgba(62, 26, 125, 0.15);
42575
+ }
42576
+
42577
+ .myio-contract-devices-modal .field-key {
42578
+ font-size: 10px;
42579
+ color: #999;
42580
+ font-family: 'Courier New', monospace;
42581
+ }
42582
+
42583
+ .myio-contract-devices-modal .modal-footer {
42584
+ padding: 16px 24px;
42585
+ border-top: 1px solid #e0e0e0;
42586
+ display: flex;
42587
+ justify-content: flex-end;
42588
+ gap: 12px;
42589
+ background: white;
42590
+ }
42591
+
42592
+ .myio-contract-devices-modal .modal-footer button {
42593
+ padding: 10px 24px;
42594
+ border: none;
42595
+ border-radius: 6px;
42596
+ font-size: 14px;
42597
+ font-weight: 500;
42598
+ cursor: pointer;
42599
+ transition: all 0.2s;
42600
+ }
42601
+
42602
+ .myio-contract-devices-modal .btn-cancel {
42603
+ background: #6c757d;
42604
+ color: white;
42605
+ }
42606
+
42607
+ .myio-contract-devices-modal .btn-cancel:hover:not(:disabled) {
42608
+ background: #545b62;
42609
+ }
42610
+
42611
+ .myio-contract-devices-modal .btn-primary {
42612
+ background: #3e1a7d;
42613
+ color: white;
42614
+ }
42615
+
42616
+ .myio-contract-devices-modal .btn-primary:hover:not(:disabled) {
42617
+ background: #2d1458;
42618
+ }
42619
+
42620
+ .myio-contract-devices-modal .modal-footer button:disabled {
42621
+ opacity: 0.6;
42622
+ cursor: not-allowed;
42623
+ }
42624
+
42625
+ /* Responsive */
42626
+ @media (max-width: 900px) {
42627
+ .myio-contract-devices-modal .form-layout {
42628
+ grid-template-columns: 1fr;
42629
+ }
42630
+
42631
+ .myio-contract-devices-modal {
42632
+ width: 95vw !important;
42633
+ }
42634
+ }
42635
+
42636
+ /* Scrollbar */
42637
+ .myio-contract-devices-modal .modal-body::-webkit-scrollbar {
42638
+ width: 6px;
42639
+ }
42640
+
42641
+ .myio-contract-devices-modal .modal-body::-webkit-scrollbar-track {
42642
+ background: #f1f1f1;
42643
+ border-radius: 3px;
42644
+ }
42645
+
42646
+ .myio-contract-devices-modal .modal-body::-webkit-scrollbar-thumb {
42647
+ background: #c1c1c1;
42648
+ border-radius: 3px;
42649
+ }
42650
+ </style>
42651
+ `;
42652
+ }
42653
+ populateForm(data) {
42654
+ const setValue = (name, value) => {
42655
+ const input = this.form.querySelector(`[name="${name}"]`);
42656
+ if (input && value !== null && value !== void 0) {
42657
+ input.value = String(value);
42658
+ }
42659
+ };
42660
+ if (data.energy) {
42661
+ setValue("energy_total", data.energy.total);
42662
+ setValue("energy_entries", data.energy.entries);
42663
+ setValue("energy_commonArea", data.energy.commonArea);
42664
+ setValue("energy_stores", data.energy.stores);
42665
+ }
42666
+ if (data.water) {
42667
+ setValue("water_total", data.water.total);
42668
+ setValue("water_entries", data.water.entries);
42669
+ setValue("water_commonArea", data.water.commonArea);
42670
+ setValue("water_stores", data.water.stores);
42671
+ }
42672
+ if (data.temperature) {
42673
+ setValue("temperature_total", data.temperature.total);
42674
+ setValue("temperature_internal", data.temperature.internal);
42675
+ setValue("temperature_stores", data.temperature.stores);
42676
+ }
42677
+ }
42678
+ attachEventListeners() {
42679
+ const closeBtn = this.modal.querySelector(".close-btn");
42680
+ if (closeBtn) {
42681
+ closeBtn.addEventListener("click", (e) => {
42682
+ e.preventDefault();
42683
+ this.config.onClose();
42684
+ });
42685
+ }
42686
+ const cancelBtn = this.modal.querySelector(".btn-cancel");
42687
+ if (cancelBtn) {
42688
+ cancelBtn.addEventListener("click", (e) => {
42689
+ e.preventDefault();
42690
+ this.config.onClose();
42691
+ });
42692
+ }
42693
+ const saveBtn = this.modal.querySelector(".btn-save");
42694
+ if (saveBtn) {
42695
+ saveBtn.addEventListener("click", async (e) => {
42696
+ e.preventDefault();
42697
+ this.hideError();
42698
+ const formData = this.getFormData();
42699
+ await this.config.onSave(formData);
42700
+ });
42701
+ }
42702
+ this.container.addEventListener("click", (e) => {
42703
+ const target = e.target;
42704
+ if (target.classList.contains("myio-contract-devices-modal-overlay") && this.config.closeOnBackdrop !== false) {
42705
+ this.config.onClose();
42706
+ }
42707
+ });
42708
+ }
42709
+ setupAccessibility() {
42710
+ const firstInput = this.modal.querySelector("input");
42711
+ if (firstInput) {
42712
+ setTimeout(() => firstInput.focus(), 100);
42713
+ }
42714
+ this.modal.setAttribute("aria-labelledby", "modal-title");
42715
+ }
42716
+ setupFocusTrap() {
42717
+ this.focusTrapElements = Array.from(
42718
+ this.modal.querySelectorAll('button, input, [tabindex]:not([tabindex="-1"])')
42719
+ );
42720
+ this.modal.addEventListener("keydown", this.handleKeyDown.bind(this));
42721
+ }
42722
+ teardownFocusTrap() {
42723
+ this.modal.removeEventListener("keydown", this.handleKeyDown.bind(this));
42724
+ }
42725
+ handleKeyDown(event) {
42726
+ if (event.key === "Escape" && this.config.closeOnBackdrop !== false) {
42727
+ event.preventDefault();
42728
+ this.config.onClose();
42729
+ return;
42730
+ }
42731
+ if (event.key === "Tab") {
42732
+ const firstElement = this.focusTrapElements[0];
42733
+ const lastElement = this.focusTrapElements[this.focusTrapElements.length - 1];
42734
+ if (event.shiftKey) {
42735
+ if (document.activeElement === firstElement) {
42736
+ event.preventDefault();
42737
+ lastElement.focus();
42738
+ }
42739
+ } else {
42740
+ if (document.activeElement === lastElement) {
42741
+ event.preventDefault();
42742
+ firstElement.focus();
42743
+ }
42744
+ }
42745
+ }
42746
+ }
42747
+ };
42748
+
42749
+ // src/components/premium-modals/contract-devices/ContractDevicesPersister.ts
42750
+ var DefaultContractDevicesPersister = class {
42751
+ jwtToken;
42752
+ tbBaseUrl;
42753
+ constructor(jwtToken, apiConfig) {
42754
+ this.jwtToken = jwtToken;
42755
+ this.tbBaseUrl = apiConfig?.tbBaseUrl || window.location.origin;
42756
+ }
42757
+ async saveDeviceCounts(customerId, counts) {
42758
+ try {
42759
+ const payload = {};
42760
+ if (counts.energy.total !== null) {
42761
+ payload[DEVICE_COUNT_KEYS.energy.total] = counts.energy.total;
42762
+ }
42763
+ if (counts.energy.entries !== null) {
42764
+ payload[DEVICE_COUNT_KEYS.energy.entries] = counts.energy.entries;
42765
+ }
42766
+ if (counts.energy.commonArea !== null) {
42767
+ payload[DEVICE_COUNT_KEYS.energy.commonArea] = counts.energy.commonArea;
42768
+ }
42769
+ if (counts.energy.stores !== null) {
42770
+ payload[DEVICE_COUNT_KEYS.energy.stores] = counts.energy.stores;
42771
+ }
42772
+ if (counts.water.total !== null) {
42773
+ payload[DEVICE_COUNT_KEYS.water.total] = counts.water.total;
42774
+ }
42775
+ if (counts.water.entries !== null) {
42776
+ payload[DEVICE_COUNT_KEYS.water.entries] = counts.water.entries;
42777
+ }
42778
+ if (counts.water.commonArea !== null) {
42779
+ payload[DEVICE_COUNT_KEYS.water.commonArea] = counts.water.commonArea;
42780
+ }
42781
+ if (counts.water.stores !== null) {
42782
+ payload[DEVICE_COUNT_KEYS.water.stores] = counts.water.stores;
42783
+ }
42784
+ if (counts.temperature.total !== null) {
42785
+ payload[DEVICE_COUNT_KEYS.temperature.total] = counts.temperature.total;
42786
+ }
42787
+ if (counts.temperature.internal !== null) {
42788
+ payload[DEVICE_COUNT_KEYS.temperature.internal] = counts.temperature.internal;
42789
+ }
42790
+ if (counts.temperature.stores !== null) {
42791
+ payload[DEVICE_COUNT_KEYS.temperature.stores] = counts.temperature.stores;
42792
+ }
42793
+ console.log("[ContractDevicesPersister] Saving to CUSTOMER SERVER_SCOPE:", payload);
42794
+ const res = await fetch(
42795
+ `${this.tbBaseUrl}/api/plugins/telemetry/CUSTOMER/${customerId}/attributes/SERVER_SCOPE`,
42796
+ {
42797
+ method: "POST",
42798
+ headers: {
42799
+ "X-Authorization": `Bearer ${this.jwtToken}`,
42800
+ "Content-Type": "application/json"
42801
+ },
42802
+ body: JSON.stringify(payload)
42803
+ }
42804
+ );
42805
+ if (!res.ok) {
42806
+ throw this.createHttpError(res.status, await res.text().catch(() => ""));
42807
+ }
42808
+ return {
42809
+ ok: true,
42810
+ updatedKeys: Object.keys(payload),
42811
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
42812
+ };
42813
+ } catch (error) {
42814
+ console.error("[ContractDevicesPersister] Save failed:", error);
42815
+ return {
42816
+ ok: false,
42817
+ error: this.mapError(error)
42818
+ };
42819
+ }
42820
+ }
42821
+ createHttpError(status, body) {
42822
+ const error = new Error(`HTTP ${status}: ${body}`);
42823
+ error.status = status;
42824
+ error.body = body;
42825
+ return error;
42826
+ }
42827
+ mapError(error) {
42828
+ const status = error.status;
42829
+ if (status === 400) {
42830
+ return {
42831
+ code: "VALIDATION_ERROR",
42832
+ message: "Dados invalidos",
42833
+ userAction: "FIX_INPUT",
42834
+ cause: error
42835
+ };
42836
+ }
42837
+ if (status === 401) {
42838
+ return {
42839
+ code: "TOKEN_EXPIRED",
42840
+ message: "Token de autenticacao expirado",
42841
+ userAction: "RE_AUTH",
42842
+ cause: error
42843
+ };
42844
+ }
42845
+ if (status === 403) {
42846
+ return {
42847
+ code: "AUTH_ERROR",
42848
+ message: "Permissao insuficiente",
42849
+ userAction: "RE_AUTH",
42850
+ cause: error
42851
+ };
42852
+ }
42853
+ if (status === 404) {
42854
+ return {
42855
+ code: "NETWORK_ERROR",
42856
+ message: "Cliente nao encontrado",
42857
+ userAction: "CONTACT_ADMIN",
42858
+ cause: error
42859
+ };
42860
+ }
42861
+ if (status >= 500) {
42862
+ return {
42863
+ code: "NETWORK_ERROR",
42864
+ message: "Erro no servidor",
42865
+ userAction: "RETRY",
42866
+ cause: error
42867
+ };
42868
+ }
42869
+ return {
42870
+ code: "UNKNOWN_ERROR",
42871
+ message: error.message || "Erro desconhecido",
42872
+ userAction: "CONTACT_ADMIN",
42873
+ cause: error
42874
+ };
42875
+ }
42876
+ };
42877
+
42878
+ // src/components/premium-modals/contract-devices/ContractDevicesFetcher.ts
42879
+ var DefaultContractDevicesFetcher = class {
42880
+ jwtToken;
42881
+ tbBaseUrl;
42882
+ constructor(jwtToken, apiConfig) {
42883
+ this.jwtToken = jwtToken;
42884
+ this.tbBaseUrl = apiConfig?.tbBaseUrl || window.location.origin;
42885
+ }
42886
+ async fetchCurrentCounts(customerId) {
42887
+ try {
42888
+ const keys = [
42889
+ DEVICE_COUNT_KEYS.energy.total,
42890
+ DEVICE_COUNT_KEYS.energy.entries,
42891
+ DEVICE_COUNT_KEYS.energy.commonArea,
42892
+ DEVICE_COUNT_KEYS.energy.stores,
42893
+ DEVICE_COUNT_KEYS.water.total,
42894
+ DEVICE_COUNT_KEYS.water.entries,
42895
+ DEVICE_COUNT_KEYS.water.commonArea,
42896
+ DEVICE_COUNT_KEYS.water.stores,
42897
+ DEVICE_COUNT_KEYS.temperature.total,
42898
+ DEVICE_COUNT_KEYS.temperature.internal,
42899
+ DEVICE_COUNT_KEYS.temperature.stores
42900
+ ];
42901
+ const url = `${this.tbBaseUrl}/api/plugins/telemetry/CUSTOMER/${customerId}/values/attributes/SERVER_SCOPE?keys=${keys.join(",")}`;
42902
+ console.log("[ContractDevicesFetcher] Fetching from:", url);
42903
+ const res = await fetch(url, {
42904
+ headers: {
42905
+ "X-Authorization": `Bearer ${this.jwtToken}`,
42906
+ "Content-Type": "application/json"
42907
+ }
42908
+ });
42909
+ if (!res.ok) {
42910
+ console.warn("[ContractDevicesFetcher] Fetch failed:", res.status);
42911
+ return {};
42912
+ }
42913
+ const data = await res.json();
42914
+ console.log("[ContractDevicesFetcher] Received data:", data);
42915
+ return this.parseAttributesToCounts(data);
42916
+ } catch (error) {
42917
+ console.error("[ContractDevicesFetcher] Error fetching counts:", error);
42918
+ return {};
42919
+ }
42920
+ }
42921
+ parseAttributesToCounts(attributes) {
42922
+ const getValue = (key) => {
42923
+ const attr = attributes.find((a) => a.key === key);
42924
+ if (!attr) return null;
42925
+ const num = parseInt(attr.value, 10);
42926
+ return isNaN(num) ? null : num;
42927
+ };
42928
+ return {
42929
+ energy: {
42930
+ total: getValue(DEVICE_COUNT_KEYS.energy.total),
42931
+ entries: getValue(DEVICE_COUNT_KEYS.energy.entries),
42932
+ commonArea: getValue(DEVICE_COUNT_KEYS.energy.commonArea),
42933
+ stores: getValue(DEVICE_COUNT_KEYS.energy.stores)
42934
+ },
42935
+ water: {
42936
+ total: getValue(DEVICE_COUNT_KEYS.water.total),
42937
+ entries: getValue(DEVICE_COUNT_KEYS.water.entries),
42938
+ commonArea: getValue(DEVICE_COUNT_KEYS.water.commonArea),
42939
+ stores: getValue(DEVICE_COUNT_KEYS.water.stores)
42940
+ },
42941
+ temperature: {
42942
+ total: getValue(DEVICE_COUNT_KEYS.temperature.total),
42943
+ internal: getValue(DEVICE_COUNT_KEYS.temperature.internal),
42944
+ stores: getValue(DEVICE_COUNT_KEYS.temperature.stores)
42945
+ }
42946
+ };
42947
+ }
42948
+ };
42949
+
42950
+ // src/components/premium-modals/contract-devices/ContractDevicesController.ts
42951
+ var ContractDevicesController = class {
42952
+ params;
42953
+ view = null;
42954
+ persister;
42955
+ fetcher;
42956
+ constructor(params) {
42957
+ this.params = params;
42958
+ this.persister = new DefaultContractDevicesPersister(
42959
+ params.jwtToken,
42960
+ params.api
42961
+ );
42962
+ this.fetcher = new DefaultContractDevicesFetcher(
42963
+ params.jwtToken,
42964
+ params.api
42965
+ );
42966
+ }
42967
+ async show() {
42968
+ let seedData = this.params.seed || {};
42969
+ try {
42970
+ const existingCounts = await this.fetcher.fetchCurrentCounts(this.params.customerId);
42971
+ seedData = this.mergeCounts(seedData, existingCounts);
42972
+ console.log("[ContractDevicesController] Merged seed data:", seedData);
42973
+ } catch (error) {
42974
+ console.warn("[ContractDevicesController] Failed to fetch existing counts:", error);
42975
+ }
42976
+ const viewConfig = {
42977
+ title: this.params.ui?.title || "Configurar Dispositivos Contratados",
42978
+ width: this.params.ui?.width || 800,
42979
+ closeOnBackdrop: this.params.ui?.closeOnBackdrop !== false,
42980
+ customerName: this.params.customerName,
42981
+ onSave: this.handleSave.bind(this),
42982
+ onClose: this.handleClose.bind(this)
42983
+ };
42984
+ this.view = new ContractDevicesModalView(viewConfig);
42985
+ this.view.render(seedData);
42986
+ }
42987
+ async handleSave(formData) {
42988
+ if (!this.view) return;
42989
+ this.view.showLoadingState(true);
42990
+ this.view.hideError();
42991
+ try {
42992
+ const result = await this.persister.saveDeviceCounts(
42993
+ this.params.customerId,
42994
+ formData
42995
+ );
42996
+ if (result.ok) {
42997
+ console.log("[ContractDevicesController] Save successful:", result);
42998
+ if (this.params.onSaved) {
42999
+ this.params.onSaved(result);
43000
+ }
43001
+ this.handleClose();
43002
+ } else {
43003
+ console.error("[ContractDevicesController] Save failed:", result.error);
43004
+ this.view.showError(result.error?.message || "Erro ao salvar configuracoes");
43005
+ if (this.params.onError && result.error) {
43006
+ this.params.onError(result.error);
43007
+ }
43008
+ }
43009
+ } catch (error) {
43010
+ console.error("[ContractDevicesController] Unexpected error:", error);
43011
+ this.view.showError(error.message || "Erro inesperado");
43012
+ if (this.params.onError) {
43013
+ this.params.onError({
43014
+ code: "UNKNOWN_ERROR",
43015
+ message: error.message || "Erro desconhecido",
43016
+ cause: error
43017
+ });
43018
+ }
43019
+ } finally {
43020
+ if (this.view) {
43021
+ this.view.showLoadingState(false);
43022
+ }
43023
+ }
43024
+ }
43025
+ handleClose() {
43026
+ if (this.view) {
43027
+ this.view.close();
43028
+ this.view = null;
43029
+ }
43030
+ if (this.params.onClose) {
43031
+ this.params.onClose();
43032
+ }
43033
+ }
43034
+ mergeCounts(seed, fetched) {
43035
+ return {
43036
+ energy: {
43037
+ total: fetched.energy?.total ?? seed.energy?.total ?? null,
43038
+ entries: fetched.energy?.entries ?? seed.energy?.entries ?? null,
43039
+ commonArea: fetched.energy?.commonArea ?? seed.energy?.commonArea ?? null,
43040
+ stores: fetched.energy?.stores ?? seed.energy?.stores ?? null
43041
+ },
43042
+ water: {
43043
+ total: fetched.water?.total ?? seed.water?.total ?? null,
43044
+ entries: fetched.water?.entries ?? seed.water?.entries ?? null,
43045
+ commonArea: fetched.water?.commonArea ?? seed.water?.commonArea ?? null,
43046
+ stores: fetched.water?.stores ?? seed.water?.stores ?? null
43047
+ },
43048
+ temperature: {
43049
+ total: fetched.temperature?.total ?? seed.temperature?.total ?? null,
43050
+ internal: fetched.temperature?.internal ?? seed.temperature?.internal ?? null,
43051
+ stores: fetched.temperature?.stores ?? seed.temperature?.stores ?? null
43052
+ }
43053
+ };
43054
+ }
43055
+ };
43056
+
43057
+ // src/components/premium-modals/contract-devices/openContractDevicesModal.ts
43058
+ async function openContractDevicesModal(params) {
43059
+ if (!params.jwtToken) {
43060
+ throw new Error("jwtToken is required for contract devices persistence");
43061
+ }
43062
+ if (!params.customerId) {
43063
+ throw new Error("customerId is required");
43064
+ }
43065
+ console.info("[openContractDevicesModal] Initializing contract devices modal", {
43066
+ customerId: params.customerId,
43067
+ customerName: params.customerName,
43068
+ hasJwtToken: !!params.jwtToken,
43069
+ hasSeedData: !!params.seed
43070
+ });
43071
+ const controller = new ContractDevicesController(params);
43072
+ try {
43073
+ await controller.show();
43074
+ } catch (error) {
43075
+ console.error("[openContractDevicesModal] Error:", error);
43076
+ if (params.onError) {
43077
+ params.onError({
43078
+ code: "UNKNOWN_ERROR",
43079
+ message: error.message || "Erro ao abrir modal de dispositivos contratados",
43080
+ cause: error
43081
+ });
43082
+ }
43083
+ throw error;
43084
+ }
43085
+ }
42158
43086
  // Annotate the CommonJS export names for ESM import in node:
42159
43087
  0 && (module.exports = {
42160
43088
  ANNOTATION_TYPE_COLORS,
@@ -42172,6 +43100,7 @@ function createDistributionChartWidget(config) {
42172
43100
  DEFAULT_GAS_GROUP_COLORS,
42173
43101
  DEFAULT_SHOPPING_COLORS,
42174
43102
  DEFAULT_WATER_GROUP_COLORS,
43103
+ DEVICE_COUNT_KEYS,
42175
43104
  DeviceComparisonTooltip,
42176
43105
  DeviceStatusType,
42177
43106
  EXPORT_DEFAULT_COLORS,
@@ -42294,6 +43223,7 @@ function createDistributionChartWidget(config) {
42294
43223
  myioExportData,
42295
43224
  normalizeRecipients,
42296
43225
  numbers,
43226
+ openContractDevicesModal,
42297
43227
  openDashboardPopup,
42298
43228
  openDashboardPopupAllReport,
42299
43229
  openDashboardPopupEnergy,