myio-js-library 0.1.200 → 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.js CHANGED
@@ -41985,6 +41985,932 @@ function createDistributionChartWidget(config) {
41985
41985
  };
41986
41986
  return instance;
41987
41987
  }
41988
+
41989
+ // src/components/premium-modals/contract-devices/types.ts
41990
+ var DEVICE_COUNT_KEYS = {
41991
+ energy: {
41992
+ total: "qtDevices3f",
41993
+ entries: "qtDevices3f-Entries",
41994
+ commonArea: "qtDevices3f-CommonArea",
41995
+ stores: "qtDevices3f-Stores"
41996
+ },
41997
+ water: {
41998
+ total: "qtDevicesHidr",
41999
+ entries: "qtDevicesHidr-Entries",
42000
+ commonArea: "qtDevicesHidr-CommonArea",
42001
+ stores: "qtDevicesHidr-Stores"
42002
+ },
42003
+ temperature: {
42004
+ total: "qtDevicesTemp",
42005
+ internal: "qtDevicesTemp-Internal",
42006
+ stores: "qtDevicesTemp-Stores"
42007
+ }
42008
+ };
42009
+
42010
+ // src/components/premium-modals/contract-devices/ContractDevicesModalView.ts
42011
+ var ContractDevicesModalView = class {
42012
+ container;
42013
+ modal;
42014
+ form;
42015
+ config;
42016
+ focusTrapElements = [];
42017
+ originalActiveElement = null;
42018
+ constructor(config) {
42019
+ this.config = config;
42020
+ this.createModal();
42021
+ }
42022
+ render(initialData) {
42023
+ this.originalActiveElement = document.activeElement;
42024
+ document.body.appendChild(this.container);
42025
+ this.populateForm(initialData);
42026
+ this.attachEventListeners();
42027
+ this.setupAccessibility();
42028
+ this.setupFocusTrap();
42029
+ }
42030
+ close() {
42031
+ this.teardownFocusTrap();
42032
+ if (this.originalActiveElement && "focus" in this.originalActiveElement) {
42033
+ this.originalActiveElement.focus();
42034
+ }
42035
+ if (this.container.parentNode) {
42036
+ this.container.parentNode.removeChild(this.container);
42037
+ }
42038
+ }
42039
+ showError(message) {
42040
+ const errorEl = this.modal.querySelector(".error-message");
42041
+ if (errorEl) {
42042
+ errorEl.textContent = message;
42043
+ errorEl.style.display = "block";
42044
+ errorEl.setAttribute("role", "alert");
42045
+ }
42046
+ }
42047
+ hideError() {
42048
+ const errorEl = this.modal.querySelector(".error-message");
42049
+ if (errorEl) {
42050
+ errorEl.style.display = "none";
42051
+ }
42052
+ }
42053
+ showLoadingState(isLoading) {
42054
+ const saveBtn = this.modal.querySelector(".btn-save");
42055
+ const cancelBtn = this.modal.querySelector(".btn-cancel");
42056
+ const formInputs = this.modal.querySelectorAll("input");
42057
+ if (saveBtn) {
42058
+ saveBtn.disabled = isLoading;
42059
+ saveBtn.textContent = isLoading ? "Salvando..." : "Salvar";
42060
+ }
42061
+ if (cancelBtn) {
42062
+ cancelBtn.disabled = isLoading;
42063
+ }
42064
+ formInputs.forEach((input) => {
42065
+ input.disabled = isLoading;
42066
+ });
42067
+ }
42068
+ getFormData() {
42069
+ const getValue = (name) => {
42070
+ const input = this.form.querySelector(`[name="${name}"]`);
42071
+ if (!input || input.value === "") return null;
42072
+ const num = parseInt(input.value, 10);
42073
+ return isNaN(num) ? null : num;
42074
+ };
42075
+ return {
42076
+ energy: {
42077
+ total: getValue("energy_total"),
42078
+ entries: getValue("energy_entries"),
42079
+ commonArea: getValue("energy_commonArea"),
42080
+ stores: getValue("energy_stores")
42081
+ },
42082
+ water: {
42083
+ total: getValue("water_total"),
42084
+ entries: getValue("water_entries"),
42085
+ commonArea: getValue("water_commonArea"),
42086
+ stores: getValue("water_stores")
42087
+ },
42088
+ temperature: {
42089
+ total: getValue("temperature_total"),
42090
+ internal: getValue("temperature_internal"),
42091
+ stores: getValue("temperature_stores")
42092
+ }
42093
+ };
42094
+ }
42095
+ createModal() {
42096
+ this.container = document.createElement("div");
42097
+ this.container.className = "myio-contract-devices-modal-overlay";
42098
+ this.container.innerHTML = this.getModalHTML();
42099
+ this.modal = this.container.querySelector(".myio-contract-devices-modal");
42100
+ this.form = this.modal.querySelector("form");
42101
+ }
42102
+ getModalHTML() {
42103
+ const width = typeof this.config.width === "number" ? `${this.config.width}px` : this.config.width;
42104
+ return `
42105
+ <div class="myio-contract-devices-modal-overlay" role="dialog" aria-modal="true" aria-labelledby="modal-title">
42106
+ <div class="myio-contract-devices-modal" style="width: ${width}">
42107
+ <div class="modal-header">
42108
+ <h3 id="modal-title">${this.config.title || "Configurar Dispositivos Contratados"}</h3>
42109
+ <button type="button" class="close-btn" aria-label="Fechar">&times;</button>
42110
+ </div>
42111
+ <div class="modal-body">
42112
+ <div class="error-message" style="display: none;" role="alert"></div>
42113
+ ${this.config.customerName ? `
42114
+ <div class="customer-info">
42115
+ <span class="customer-label">Shopping:</span>
42116
+ <span class="customer-name">${this.config.customerName}</span>
42117
+ </div>
42118
+ ` : ""}
42119
+ <form novalidate>
42120
+ ${this.getFormHTML()}
42121
+ </form>
42122
+ </div>
42123
+ <div class="modal-footer">
42124
+ <button type="button" class="btn-cancel">Fechar</button>
42125
+ <button type="button" class="btn-save btn-primary">Salvar</button>
42126
+ </div>
42127
+ </div>
42128
+ </div>
42129
+ ${this.getModalCSS()}
42130
+ `;
42131
+ }
42132
+ getFormHTML() {
42133
+ return `
42134
+ <div class="form-layout">
42135
+ <!-- Energy Section -->
42136
+ <div class="domain-card energy-card">
42137
+ <div class="domain-header">
42138
+ <span class="domain-icon">&#9889;</span>
42139
+ <h4>Energia</h4>
42140
+ </div>
42141
+ <div class="domain-fields">
42142
+ <div class="field-group">
42143
+ <label for="energy_total">Total Contratado</label>
42144
+ <input type="number" id="energy_total" name="energy_total" min="0" step="1" placeholder="0">
42145
+ <small class="field-key">${DEVICE_COUNT_KEYS.energy.total}</small>
42146
+ </div>
42147
+ <div class="field-group">
42148
+ <label for="energy_entries">Entradas</label>
42149
+ <input type="number" id="energy_entries" name="energy_entries" min="0" step="1" placeholder="0">
42150
+ <small class="field-key">${DEVICE_COUNT_KEYS.energy.entries}</small>
42151
+ </div>
42152
+ <div class="field-group">
42153
+ <label for="energy_commonArea">Area Comum</label>
42154
+ <input type="number" id="energy_commonArea" name="energy_commonArea" min="0" step="1" placeholder="0">
42155
+ <small class="field-key">${DEVICE_COUNT_KEYS.energy.commonArea}</small>
42156
+ </div>
42157
+ <div class="field-group">
42158
+ <label for="energy_stores">Lojas</label>
42159
+ <input type="number" id="energy_stores" name="energy_stores" min="0" step="1" placeholder="0">
42160
+ <small class="field-key">${DEVICE_COUNT_KEYS.energy.stores}</small>
42161
+ </div>
42162
+ </div>
42163
+ </div>
42164
+
42165
+ <!-- Water Section -->
42166
+ <div class="domain-card water-card">
42167
+ <div class="domain-header">
42168
+ <span class="domain-icon">&#128167;</span>
42169
+ <h4>Agua</h4>
42170
+ </div>
42171
+ <div class="domain-fields">
42172
+ <div class="field-group">
42173
+ <label for="water_total">Total Contratado</label>
42174
+ <input type="number" id="water_total" name="water_total" min="0" step="1" placeholder="0">
42175
+ <small class="field-key">${DEVICE_COUNT_KEYS.water.total}</small>
42176
+ </div>
42177
+ <div class="field-group">
42178
+ <label for="water_entries">Entradas</label>
42179
+ <input type="number" id="water_entries" name="water_entries" min="0" step="1" placeholder="0">
42180
+ <small class="field-key">${DEVICE_COUNT_KEYS.water.entries}</small>
42181
+ </div>
42182
+ <div class="field-group">
42183
+ <label for="water_commonArea">Area Comum</label>
42184
+ <input type="number" id="water_commonArea" name="water_commonArea" min="0" step="1" placeholder="0">
42185
+ <small class="field-key">${DEVICE_COUNT_KEYS.water.commonArea}</small>
42186
+ </div>
42187
+ <div class="field-group">
42188
+ <label for="water_stores">Lojas</label>
42189
+ <input type="number" id="water_stores" name="water_stores" min="0" step="1" placeholder="0">
42190
+ <small class="field-key">${DEVICE_COUNT_KEYS.water.stores}</small>
42191
+ </div>
42192
+ </div>
42193
+ </div>
42194
+
42195
+ <!-- Temperature Section -->
42196
+ <div class="domain-card temperature-card">
42197
+ <div class="domain-header">
42198
+ <span class="domain-icon">&#127777;</span>
42199
+ <h4>Temperatura</h4>
42200
+ </div>
42201
+ <div class="domain-fields">
42202
+ <div class="field-group">
42203
+ <label for="temperature_total">Total Contratado</label>
42204
+ <input type="number" id="temperature_total" name="temperature_total" min="0" step="1" placeholder="0">
42205
+ <small class="field-key">${DEVICE_COUNT_KEYS.temperature.total}</small>
42206
+ </div>
42207
+ <div class="field-group">
42208
+ <label for="temperature_internal">Sensores Internos</label>
42209
+ <input type="number" id="temperature_internal" name="temperature_internal" min="0" step="1" placeholder="0">
42210
+ <small class="field-key">${DEVICE_COUNT_KEYS.temperature.internal}</small>
42211
+ </div>
42212
+ <div class="field-group">
42213
+ <label for="temperature_stores">Lojas</label>
42214
+ <input type="number" id="temperature_stores" name="temperature_stores" min="0" step="1" placeholder="0">
42215
+ <small class="field-key">${DEVICE_COUNT_KEYS.temperature.stores}</small>
42216
+ </div>
42217
+ </div>
42218
+ </div>
42219
+ </div>
42220
+ `;
42221
+ }
42222
+ getModalCSS() {
42223
+ return `
42224
+ <style>
42225
+ .myio-contract-devices-modal-overlay {
42226
+ position: fixed;
42227
+ top: 0;
42228
+ left: 0;
42229
+ right: 0;
42230
+ bottom: 0;
42231
+ background: rgba(0, 0, 0, 0.5);
42232
+ display: flex;
42233
+ align-items: center;
42234
+ justify-content: center;
42235
+ z-index: 10000;
42236
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
42237
+ }
42238
+
42239
+ .myio-contract-devices-modal {
42240
+ background: white;
42241
+ border-radius: 12px;
42242
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.25);
42243
+ max-width: 95vw;
42244
+ max-height: 90vh;
42245
+ width: 800px;
42246
+ overflow: hidden;
42247
+ display: flex;
42248
+ flex-direction: column;
42249
+ }
42250
+
42251
+ .myio-contract-devices-modal .modal-header {
42252
+ background: linear-gradient(135deg, #3e1a7d 0%, #5c2d91 100%);
42253
+ color: white;
42254
+ padding: 20px 24px;
42255
+ display: flex;
42256
+ justify-content: space-between;
42257
+ align-items: center;
42258
+ }
42259
+
42260
+ .myio-contract-devices-modal .modal-header h3 {
42261
+ margin: 0;
42262
+ font-size: 18px;
42263
+ font-weight: 600;
42264
+ color: white;
42265
+ }
42266
+
42267
+ .myio-contract-devices-modal .close-btn {
42268
+ background: none;
42269
+ border: none;
42270
+ font-size: 24px;
42271
+ cursor: pointer;
42272
+ color: white;
42273
+ padding: 0;
42274
+ width: 32px;
42275
+ height: 32px;
42276
+ display: flex;
42277
+ align-items: center;
42278
+ justify-content: center;
42279
+ border-radius: 4px;
42280
+ transition: background 0.2s;
42281
+ }
42282
+
42283
+ .myio-contract-devices-modal .close-btn:hover {
42284
+ background: rgba(255, 255, 255, 0.1);
42285
+ }
42286
+
42287
+ .myio-contract-devices-modal .modal-body {
42288
+ padding: 24px;
42289
+ overflow-y: auto;
42290
+ flex: 1;
42291
+ background: #f8f9fa;
42292
+ }
42293
+
42294
+ .myio-contract-devices-modal .error-message {
42295
+ background: #fee;
42296
+ border: 1px solid #fcc;
42297
+ color: #c33;
42298
+ padding: 12px;
42299
+ border-radius: 6px;
42300
+ margin-bottom: 16px;
42301
+ font-size: 14px;
42302
+ }
42303
+
42304
+ .myio-contract-devices-modal .customer-info {
42305
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
42306
+ padding: 16px 20px;
42307
+ border-radius: 8px;
42308
+ margin-bottom: 20px;
42309
+ display: flex;
42310
+ align-items: center;
42311
+ gap: 10px;
42312
+ }
42313
+
42314
+ .myio-contract-devices-modal .customer-label {
42315
+ color: rgba(255, 255, 255, 0.8);
42316
+ font-size: 13px;
42317
+ font-weight: 500;
42318
+ }
42319
+
42320
+ .myio-contract-devices-modal .customer-name {
42321
+ color: white;
42322
+ font-size: 16px;
42323
+ font-weight: 600;
42324
+ }
42325
+
42326
+ .myio-contract-devices-modal .form-layout {
42327
+ display: grid;
42328
+ grid-template-columns: repeat(3, 1fr);
42329
+ gap: 20px;
42330
+ }
42331
+
42332
+ .myio-contract-devices-modal .domain-card {
42333
+ background: white;
42334
+ border-radius: 10px;
42335
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
42336
+ overflow: hidden;
42337
+ }
42338
+
42339
+ .myio-contract-devices-modal .domain-header {
42340
+ padding: 14px 16px;
42341
+ display: flex;
42342
+ align-items: center;
42343
+ gap: 10px;
42344
+ border-bottom: 1px solid #eee;
42345
+ }
42346
+
42347
+ .myio-contract-devices-modal .domain-header h4 {
42348
+ margin: 0;
42349
+ font-size: 15px;
42350
+ font-weight: 600;
42351
+ color: #333;
42352
+ }
42353
+
42354
+ .myio-contract-devices-modal .domain-icon {
42355
+ font-size: 20px;
42356
+ }
42357
+
42358
+ .myio-contract-devices-modal .energy-card .domain-header {
42359
+ background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
42360
+ }
42361
+
42362
+ .myio-contract-devices-modal .water-card .domain-header {
42363
+ background: linear-gradient(135deg, #dbeafe 0%, #93c5fd 100%);
42364
+ }
42365
+
42366
+ .myio-contract-devices-modal .temperature-card .domain-header {
42367
+ background: linear-gradient(135deg, #fce7f3 0%, #f9a8d4 100%);
42368
+ }
42369
+
42370
+ .myio-contract-devices-modal .domain-fields {
42371
+ padding: 16px;
42372
+ display: flex;
42373
+ flex-direction: column;
42374
+ gap: 14px;
42375
+ }
42376
+
42377
+ .myio-contract-devices-modal .field-group {
42378
+ display: flex;
42379
+ flex-direction: column;
42380
+ gap: 4px;
42381
+ }
42382
+
42383
+ .myio-contract-devices-modal .field-group label {
42384
+ font-size: 13px;
42385
+ font-weight: 500;
42386
+ color: #555;
42387
+ }
42388
+
42389
+ .myio-contract-devices-modal .field-group input {
42390
+ width: 100%;
42391
+ padding: 10px 12px;
42392
+ border: 1px solid #ddd;
42393
+ border-radius: 6px;
42394
+ font-size: 14px;
42395
+ transition: border-color 0.2s, box-shadow 0.2s;
42396
+ box-sizing: border-box;
42397
+ }
42398
+
42399
+ .myio-contract-devices-modal .field-group input:focus {
42400
+ outline: none;
42401
+ border-color: #3e1a7d;
42402
+ box-shadow: 0 0 0 3px rgba(62, 26, 125, 0.15);
42403
+ }
42404
+
42405
+ .myio-contract-devices-modal .field-key {
42406
+ font-size: 10px;
42407
+ color: #999;
42408
+ font-family: 'Courier New', monospace;
42409
+ }
42410
+
42411
+ .myio-contract-devices-modal .modal-footer {
42412
+ padding: 16px 24px;
42413
+ border-top: 1px solid #e0e0e0;
42414
+ display: flex;
42415
+ justify-content: flex-end;
42416
+ gap: 12px;
42417
+ background: white;
42418
+ }
42419
+
42420
+ .myio-contract-devices-modal .modal-footer button {
42421
+ padding: 10px 24px;
42422
+ border: none;
42423
+ border-radius: 6px;
42424
+ font-size: 14px;
42425
+ font-weight: 500;
42426
+ cursor: pointer;
42427
+ transition: all 0.2s;
42428
+ }
42429
+
42430
+ .myio-contract-devices-modal .btn-cancel {
42431
+ background: #6c757d;
42432
+ color: white;
42433
+ }
42434
+
42435
+ .myio-contract-devices-modal .btn-cancel:hover:not(:disabled) {
42436
+ background: #545b62;
42437
+ }
42438
+
42439
+ .myio-contract-devices-modal .btn-primary {
42440
+ background: #3e1a7d;
42441
+ color: white;
42442
+ }
42443
+
42444
+ .myio-contract-devices-modal .btn-primary:hover:not(:disabled) {
42445
+ background: #2d1458;
42446
+ }
42447
+
42448
+ .myio-contract-devices-modal .modal-footer button:disabled {
42449
+ opacity: 0.6;
42450
+ cursor: not-allowed;
42451
+ }
42452
+
42453
+ /* Responsive */
42454
+ @media (max-width: 900px) {
42455
+ .myio-contract-devices-modal .form-layout {
42456
+ grid-template-columns: 1fr;
42457
+ }
42458
+
42459
+ .myio-contract-devices-modal {
42460
+ width: 95vw !important;
42461
+ }
42462
+ }
42463
+
42464
+ /* Scrollbar */
42465
+ .myio-contract-devices-modal .modal-body::-webkit-scrollbar {
42466
+ width: 6px;
42467
+ }
42468
+
42469
+ .myio-contract-devices-modal .modal-body::-webkit-scrollbar-track {
42470
+ background: #f1f1f1;
42471
+ border-radius: 3px;
42472
+ }
42473
+
42474
+ .myio-contract-devices-modal .modal-body::-webkit-scrollbar-thumb {
42475
+ background: #c1c1c1;
42476
+ border-radius: 3px;
42477
+ }
42478
+ </style>
42479
+ `;
42480
+ }
42481
+ populateForm(data) {
42482
+ const setValue = (name, value) => {
42483
+ const input = this.form.querySelector(`[name="${name}"]`);
42484
+ if (input && value !== null && value !== void 0) {
42485
+ input.value = String(value);
42486
+ }
42487
+ };
42488
+ if (data.energy) {
42489
+ setValue("energy_total", data.energy.total);
42490
+ setValue("energy_entries", data.energy.entries);
42491
+ setValue("energy_commonArea", data.energy.commonArea);
42492
+ setValue("energy_stores", data.energy.stores);
42493
+ }
42494
+ if (data.water) {
42495
+ setValue("water_total", data.water.total);
42496
+ setValue("water_entries", data.water.entries);
42497
+ setValue("water_commonArea", data.water.commonArea);
42498
+ setValue("water_stores", data.water.stores);
42499
+ }
42500
+ if (data.temperature) {
42501
+ setValue("temperature_total", data.temperature.total);
42502
+ setValue("temperature_internal", data.temperature.internal);
42503
+ setValue("temperature_stores", data.temperature.stores);
42504
+ }
42505
+ }
42506
+ attachEventListeners() {
42507
+ const closeBtn = this.modal.querySelector(".close-btn");
42508
+ if (closeBtn) {
42509
+ closeBtn.addEventListener("click", (e) => {
42510
+ e.preventDefault();
42511
+ this.config.onClose();
42512
+ });
42513
+ }
42514
+ const cancelBtn = this.modal.querySelector(".btn-cancel");
42515
+ if (cancelBtn) {
42516
+ cancelBtn.addEventListener("click", (e) => {
42517
+ e.preventDefault();
42518
+ this.config.onClose();
42519
+ });
42520
+ }
42521
+ const saveBtn = this.modal.querySelector(".btn-save");
42522
+ if (saveBtn) {
42523
+ saveBtn.addEventListener("click", async (e) => {
42524
+ e.preventDefault();
42525
+ this.hideError();
42526
+ const formData = this.getFormData();
42527
+ await this.config.onSave(formData);
42528
+ });
42529
+ }
42530
+ this.container.addEventListener("click", (e) => {
42531
+ const target = e.target;
42532
+ if (target.classList.contains("myio-contract-devices-modal-overlay") && this.config.closeOnBackdrop !== false) {
42533
+ this.config.onClose();
42534
+ }
42535
+ });
42536
+ }
42537
+ setupAccessibility() {
42538
+ const firstInput = this.modal.querySelector("input");
42539
+ if (firstInput) {
42540
+ setTimeout(() => firstInput.focus(), 100);
42541
+ }
42542
+ this.modal.setAttribute("aria-labelledby", "modal-title");
42543
+ }
42544
+ setupFocusTrap() {
42545
+ this.focusTrapElements = Array.from(
42546
+ this.modal.querySelectorAll('button, input, [tabindex]:not([tabindex="-1"])')
42547
+ );
42548
+ this.modal.addEventListener("keydown", this.handleKeyDown.bind(this));
42549
+ }
42550
+ teardownFocusTrap() {
42551
+ this.modal.removeEventListener("keydown", this.handleKeyDown.bind(this));
42552
+ }
42553
+ handleKeyDown(event) {
42554
+ if (event.key === "Escape" && this.config.closeOnBackdrop !== false) {
42555
+ event.preventDefault();
42556
+ this.config.onClose();
42557
+ return;
42558
+ }
42559
+ if (event.key === "Tab") {
42560
+ const firstElement = this.focusTrapElements[0];
42561
+ const lastElement = this.focusTrapElements[this.focusTrapElements.length - 1];
42562
+ if (event.shiftKey) {
42563
+ if (document.activeElement === firstElement) {
42564
+ event.preventDefault();
42565
+ lastElement.focus();
42566
+ }
42567
+ } else {
42568
+ if (document.activeElement === lastElement) {
42569
+ event.preventDefault();
42570
+ firstElement.focus();
42571
+ }
42572
+ }
42573
+ }
42574
+ }
42575
+ };
42576
+
42577
+ // src/components/premium-modals/contract-devices/ContractDevicesPersister.ts
42578
+ var DefaultContractDevicesPersister = class {
42579
+ jwtToken;
42580
+ tbBaseUrl;
42581
+ constructor(jwtToken, apiConfig) {
42582
+ this.jwtToken = jwtToken;
42583
+ this.tbBaseUrl = apiConfig?.tbBaseUrl || window.location.origin;
42584
+ }
42585
+ async saveDeviceCounts(customerId, counts) {
42586
+ try {
42587
+ const payload = {};
42588
+ if (counts.energy.total !== null) {
42589
+ payload[DEVICE_COUNT_KEYS.energy.total] = counts.energy.total;
42590
+ }
42591
+ if (counts.energy.entries !== null) {
42592
+ payload[DEVICE_COUNT_KEYS.energy.entries] = counts.energy.entries;
42593
+ }
42594
+ if (counts.energy.commonArea !== null) {
42595
+ payload[DEVICE_COUNT_KEYS.energy.commonArea] = counts.energy.commonArea;
42596
+ }
42597
+ if (counts.energy.stores !== null) {
42598
+ payload[DEVICE_COUNT_KEYS.energy.stores] = counts.energy.stores;
42599
+ }
42600
+ if (counts.water.total !== null) {
42601
+ payload[DEVICE_COUNT_KEYS.water.total] = counts.water.total;
42602
+ }
42603
+ if (counts.water.entries !== null) {
42604
+ payload[DEVICE_COUNT_KEYS.water.entries] = counts.water.entries;
42605
+ }
42606
+ if (counts.water.commonArea !== null) {
42607
+ payload[DEVICE_COUNT_KEYS.water.commonArea] = counts.water.commonArea;
42608
+ }
42609
+ if (counts.water.stores !== null) {
42610
+ payload[DEVICE_COUNT_KEYS.water.stores] = counts.water.stores;
42611
+ }
42612
+ if (counts.temperature.total !== null) {
42613
+ payload[DEVICE_COUNT_KEYS.temperature.total] = counts.temperature.total;
42614
+ }
42615
+ if (counts.temperature.internal !== null) {
42616
+ payload[DEVICE_COUNT_KEYS.temperature.internal] = counts.temperature.internal;
42617
+ }
42618
+ if (counts.temperature.stores !== null) {
42619
+ payload[DEVICE_COUNT_KEYS.temperature.stores] = counts.temperature.stores;
42620
+ }
42621
+ console.log("[ContractDevicesPersister] Saving to CUSTOMER SERVER_SCOPE:", payload);
42622
+ const res = await fetch(
42623
+ `${this.tbBaseUrl}/api/plugins/telemetry/CUSTOMER/${customerId}/attributes/SERVER_SCOPE`,
42624
+ {
42625
+ method: "POST",
42626
+ headers: {
42627
+ "X-Authorization": `Bearer ${this.jwtToken}`,
42628
+ "Content-Type": "application/json"
42629
+ },
42630
+ body: JSON.stringify(payload)
42631
+ }
42632
+ );
42633
+ if (!res.ok) {
42634
+ throw this.createHttpError(res.status, await res.text().catch(() => ""));
42635
+ }
42636
+ return {
42637
+ ok: true,
42638
+ updatedKeys: Object.keys(payload),
42639
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
42640
+ };
42641
+ } catch (error) {
42642
+ console.error("[ContractDevicesPersister] Save failed:", error);
42643
+ return {
42644
+ ok: false,
42645
+ error: this.mapError(error)
42646
+ };
42647
+ }
42648
+ }
42649
+ createHttpError(status, body) {
42650
+ const error = new Error(`HTTP ${status}: ${body}`);
42651
+ error.status = status;
42652
+ error.body = body;
42653
+ return error;
42654
+ }
42655
+ mapError(error) {
42656
+ const status = error.status;
42657
+ if (status === 400) {
42658
+ return {
42659
+ code: "VALIDATION_ERROR",
42660
+ message: "Dados invalidos",
42661
+ userAction: "FIX_INPUT",
42662
+ cause: error
42663
+ };
42664
+ }
42665
+ if (status === 401) {
42666
+ return {
42667
+ code: "TOKEN_EXPIRED",
42668
+ message: "Token de autenticacao expirado",
42669
+ userAction: "RE_AUTH",
42670
+ cause: error
42671
+ };
42672
+ }
42673
+ if (status === 403) {
42674
+ return {
42675
+ code: "AUTH_ERROR",
42676
+ message: "Permissao insuficiente",
42677
+ userAction: "RE_AUTH",
42678
+ cause: error
42679
+ };
42680
+ }
42681
+ if (status === 404) {
42682
+ return {
42683
+ code: "NETWORK_ERROR",
42684
+ message: "Cliente nao encontrado",
42685
+ userAction: "CONTACT_ADMIN",
42686
+ cause: error
42687
+ };
42688
+ }
42689
+ if (status >= 500) {
42690
+ return {
42691
+ code: "NETWORK_ERROR",
42692
+ message: "Erro no servidor",
42693
+ userAction: "RETRY",
42694
+ cause: error
42695
+ };
42696
+ }
42697
+ return {
42698
+ code: "UNKNOWN_ERROR",
42699
+ message: error.message || "Erro desconhecido",
42700
+ userAction: "CONTACT_ADMIN",
42701
+ cause: error
42702
+ };
42703
+ }
42704
+ };
42705
+
42706
+ // src/components/premium-modals/contract-devices/ContractDevicesFetcher.ts
42707
+ var DefaultContractDevicesFetcher = class {
42708
+ jwtToken;
42709
+ tbBaseUrl;
42710
+ constructor(jwtToken, apiConfig) {
42711
+ this.jwtToken = jwtToken;
42712
+ this.tbBaseUrl = apiConfig?.tbBaseUrl || window.location.origin;
42713
+ }
42714
+ async fetchCurrentCounts(customerId) {
42715
+ try {
42716
+ const keys = [
42717
+ DEVICE_COUNT_KEYS.energy.total,
42718
+ DEVICE_COUNT_KEYS.energy.entries,
42719
+ DEVICE_COUNT_KEYS.energy.commonArea,
42720
+ DEVICE_COUNT_KEYS.energy.stores,
42721
+ DEVICE_COUNT_KEYS.water.total,
42722
+ DEVICE_COUNT_KEYS.water.entries,
42723
+ DEVICE_COUNT_KEYS.water.commonArea,
42724
+ DEVICE_COUNT_KEYS.water.stores,
42725
+ DEVICE_COUNT_KEYS.temperature.total,
42726
+ DEVICE_COUNT_KEYS.temperature.internal,
42727
+ DEVICE_COUNT_KEYS.temperature.stores
42728
+ ];
42729
+ const url = `${this.tbBaseUrl}/api/plugins/telemetry/CUSTOMER/${customerId}/values/attributes/SERVER_SCOPE?keys=${keys.join(",")}`;
42730
+ console.log("[ContractDevicesFetcher] Fetching from:", url);
42731
+ const res = await fetch(url, {
42732
+ headers: {
42733
+ "X-Authorization": `Bearer ${this.jwtToken}`,
42734
+ "Content-Type": "application/json"
42735
+ }
42736
+ });
42737
+ if (!res.ok) {
42738
+ console.warn("[ContractDevicesFetcher] Fetch failed:", res.status);
42739
+ return {};
42740
+ }
42741
+ const data = await res.json();
42742
+ console.log("[ContractDevicesFetcher] Received data:", data);
42743
+ return this.parseAttributesToCounts(data);
42744
+ } catch (error) {
42745
+ console.error("[ContractDevicesFetcher] Error fetching counts:", error);
42746
+ return {};
42747
+ }
42748
+ }
42749
+ parseAttributesToCounts(attributes) {
42750
+ const getValue = (key) => {
42751
+ const attr = attributes.find((a) => a.key === key);
42752
+ if (!attr) return null;
42753
+ const num = parseInt(attr.value, 10);
42754
+ return isNaN(num) ? null : num;
42755
+ };
42756
+ return {
42757
+ energy: {
42758
+ total: getValue(DEVICE_COUNT_KEYS.energy.total),
42759
+ entries: getValue(DEVICE_COUNT_KEYS.energy.entries),
42760
+ commonArea: getValue(DEVICE_COUNT_KEYS.energy.commonArea),
42761
+ stores: getValue(DEVICE_COUNT_KEYS.energy.stores)
42762
+ },
42763
+ water: {
42764
+ total: getValue(DEVICE_COUNT_KEYS.water.total),
42765
+ entries: getValue(DEVICE_COUNT_KEYS.water.entries),
42766
+ commonArea: getValue(DEVICE_COUNT_KEYS.water.commonArea),
42767
+ stores: getValue(DEVICE_COUNT_KEYS.water.stores)
42768
+ },
42769
+ temperature: {
42770
+ total: getValue(DEVICE_COUNT_KEYS.temperature.total),
42771
+ internal: getValue(DEVICE_COUNT_KEYS.temperature.internal),
42772
+ stores: getValue(DEVICE_COUNT_KEYS.temperature.stores)
42773
+ }
42774
+ };
42775
+ }
42776
+ };
42777
+
42778
+ // src/components/premium-modals/contract-devices/ContractDevicesController.ts
42779
+ var ContractDevicesController = class {
42780
+ params;
42781
+ view = null;
42782
+ persister;
42783
+ fetcher;
42784
+ constructor(params) {
42785
+ this.params = params;
42786
+ this.persister = new DefaultContractDevicesPersister(
42787
+ params.jwtToken,
42788
+ params.api
42789
+ );
42790
+ this.fetcher = new DefaultContractDevicesFetcher(
42791
+ params.jwtToken,
42792
+ params.api
42793
+ );
42794
+ }
42795
+ async show() {
42796
+ let seedData = this.params.seed || {};
42797
+ try {
42798
+ const existingCounts = await this.fetcher.fetchCurrentCounts(this.params.customerId);
42799
+ seedData = this.mergeCounts(seedData, existingCounts);
42800
+ console.log("[ContractDevicesController] Merged seed data:", seedData);
42801
+ } catch (error) {
42802
+ console.warn("[ContractDevicesController] Failed to fetch existing counts:", error);
42803
+ }
42804
+ const viewConfig = {
42805
+ title: this.params.ui?.title || "Configurar Dispositivos Contratados",
42806
+ width: this.params.ui?.width || 800,
42807
+ closeOnBackdrop: this.params.ui?.closeOnBackdrop !== false,
42808
+ customerName: this.params.customerName,
42809
+ onSave: this.handleSave.bind(this),
42810
+ onClose: this.handleClose.bind(this)
42811
+ };
42812
+ this.view = new ContractDevicesModalView(viewConfig);
42813
+ this.view.render(seedData);
42814
+ }
42815
+ async handleSave(formData) {
42816
+ if (!this.view) return;
42817
+ this.view.showLoadingState(true);
42818
+ this.view.hideError();
42819
+ try {
42820
+ const result = await this.persister.saveDeviceCounts(
42821
+ this.params.customerId,
42822
+ formData
42823
+ );
42824
+ if (result.ok) {
42825
+ console.log("[ContractDevicesController] Save successful:", result);
42826
+ if (this.params.onSaved) {
42827
+ this.params.onSaved(result);
42828
+ }
42829
+ this.handleClose();
42830
+ } else {
42831
+ console.error("[ContractDevicesController] Save failed:", result.error);
42832
+ this.view.showError(result.error?.message || "Erro ao salvar configuracoes");
42833
+ if (this.params.onError && result.error) {
42834
+ this.params.onError(result.error);
42835
+ }
42836
+ }
42837
+ } catch (error) {
42838
+ console.error("[ContractDevicesController] Unexpected error:", error);
42839
+ this.view.showError(error.message || "Erro inesperado");
42840
+ if (this.params.onError) {
42841
+ this.params.onError({
42842
+ code: "UNKNOWN_ERROR",
42843
+ message: error.message || "Erro desconhecido",
42844
+ cause: error
42845
+ });
42846
+ }
42847
+ } finally {
42848
+ if (this.view) {
42849
+ this.view.showLoadingState(false);
42850
+ }
42851
+ }
42852
+ }
42853
+ handleClose() {
42854
+ if (this.view) {
42855
+ this.view.close();
42856
+ this.view = null;
42857
+ }
42858
+ if (this.params.onClose) {
42859
+ this.params.onClose();
42860
+ }
42861
+ }
42862
+ mergeCounts(seed, fetched) {
42863
+ return {
42864
+ energy: {
42865
+ total: fetched.energy?.total ?? seed.energy?.total ?? null,
42866
+ entries: fetched.energy?.entries ?? seed.energy?.entries ?? null,
42867
+ commonArea: fetched.energy?.commonArea ?? seed.energy?.commonArea ?? null,
42868
+ stores: fetched.energy?.stores ?? seed.energy?.stores ?? null
42869
+ },
42870
+ water: {
42871
+ total: fetched.water?.total ?? seed.water?.total ?? null,
42872
+ entries: fetched.water?.entries ?? seed.water?.entries ?? null,
42873
+ commonArea: fetched.water?.commonArea ?? seed.water?.commonArea ?? null,
42874
+ stores: fetched.water?.stores ?? seed.water?.stores ?? null
42875
+ },
42876
+ temperature: {
42877
+ total: fetched.temperature?.total ?? seed.temperature?.total ?? null,
42878
+ internal: fetched.temperature?.internal ?? seed.temperature?.internal ?? null,
42879
+ stores: fetched.temperature?.stores ?? seed.temperature?.stores ?? null
42880
+ }
42881
+ };
42882
+ }
42883
+ };
42884
+
42885
+ // src/components/premium-modals/contract-devices/openContractDevicesModal.ts
42886
+ async function openContractDevicesModal(params) {
42887
+ if (!params.jwtToken) {
42888
+ throw new Error("jwtToken is required for contract devices persistence");
42889
+ }
42890
+ if (!params.customerId) {
42891
+ throw new Error("customerId is required");
42892
+ }
42893
+ console.info("[openContractDevicesModal] Initializing contract devices modal", {
42894
+ customerId: params.customerId,
42895
+ customerName: params.customerName,
42896
+ hasJwtToken: !!params.jwtToken,
42897
+ hasSeedData: !!params.seed
42898
+ });
42899
+ const controller = new ContractDevicesController(params);
42900
+ try {
42901
+ await controller.show();
42902
+ } catch (error) {
42903
+ console.error("[openContractDevicesModal] Error:", error);
42904
+ if (params.onError) {
42905
+ params.onError({
42906
+ code: "UNKNOWN_ERROR",
42907
+ message: error.message || "Erro ao abrir modal de dispositivos contratados",
42908
+ cause: error
42909
+ });
42910
+ }
42911
+ throw error;
42912
+ }
42913
+ }
41988
42914
  export {
41989
42915
  ANNOTATION_TYPE_COLORS,
41990
42916
  ANNOTATION_TYPE_LABELS,
@@ -42001,6 +42927,7 @@ export {
42001
42927
  DEFAULT_GAS_GROUP_COLORS,
42002
42928
  DEFAULT_SHOPPING_COLORS,
42003
42929
  DEFAULT_WATER_GROUP_COLORS,
42930
+ DEVICE_COUNT_KEYS,
42004
42931
  DeviceComparisonTooltip,
42005
42932
  DeviceStatusType,
42006
42933
  EXPORT_DEFAULT_COLORS,
@@ -42123,6 +43050,7 @@ export {
42123
43050
  myioExportData,
42124
43051
  normalizeRecipients,
42125
43052
  numbers_exports as numbers,
43053
+ openContractDevicesModal,
42126
43054
  openDashboardPopup,
42127
43055
  openDashboardPopupAllReport,
42128
43056
  openDashboardPopupEnergy,