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.
@@ -41795,6 +41795,932 @@
41795
41795
  return instance;
41796
41796
  }
41797
41797
 
41798
+ // src/components/premium-modals/contract-devices/types.ts
41799
+ var DEVICE_COUNT_KEYS = {
41800
+ energy: {
41801
+ total: "qtDevices3f",
41802
+ entries: "qtDevices3f-Entries",
41803
+ commonArea: "qtDevices3f-CommonArea",
41804
+ stores: "qtDevices3f-Stores"
41805
+ },
41806
+ water: {
41807
+ total: "qtDevicesHidr",
41808
+ entries: "qtDevicesHidr-Entries",
41809
+ commonArea: "qtDevicesHidr-CommonArea",
41810
+ stores: "qtDevicesHidr-Stores"
41811
+ },
41812
+ temperature: {
41813
+ total: "qtDevicesTemp",
41814
+ internal: "qtDevicesTemp-Internal",
41815
+ stores: "qtDevicesTemp-Stores"
41816
+ }
41817
+ };
41818
+
41819
+ // src/components/premium-modals/contract-devices/ContractDevicesModalView.ts
41820
+ var ContractDevicesModalView = class {
41821
+ container;
41822
+ modal;
41823
+ form;
41824
+ config;
41825
+ focusTrapElements = [];
41826
+ originalActiveElement = null;
41827
+ constructor(config) {
41828
+ this.config = config;
41829
+ this.createModal();
41830
+ }
41831
+ render(initialData) {
41832
+ this.originalActiveElement = document.activeElement;
41833
+ document.body.appendChild(this.container);
41834
+ this.populateForm(initialData);
41835
+ this.attachEventListeners();
41836
+ this.setupAccessibility();
41837
+ this.setupFocusTrap();
41838
+ }
41839
+ close() {
41840
+ this.teardownFocusTrap();
41841
+ if (this.originalActiveElement && "focus" in this.originalActiveElement) {
41842
+ this.originalActiveElement.focus();
41843
+ }
41844
+ if (this.container.parentNode) {
41845
+ this.container.parentNode.removeChild(this.container);
41846
+ }
41847
+ }
41848
+ showError(message) {
41849
+ const errorEl = this.modal.querySelector(".error-message");
41850
+ if (errorEl) {
41851
+ errorEl.textContent = message;
41852
+ errorEl.style.display = "block";
41853
+ errorEl.setAttribute("role", "alert");
41854
+ }
41855
+ }
41856
+ hideError() {
41857
+ const errorEl = this.modal.querySelector(".error-message");
41858
+ if (errorEl) {
41859
+ errorEl.style.display = "none";
41860
+ }
41861
+ }
41862
+ showLoadingState(isLoading) {
41863
+ const saveBtn = this.modal.querySelector(".btn-save");
41864
+ const cancelBtn = this.modal.querySelector(".btn-cancel");
41865
+ const formInputs = this.modal.querySelectorAll("input");
41866
+ if (saveBtn) {
41867
+ saveBtn.disabled = isLoading;
41868
+ saveBtn.textContent = isLoading ? "Salvando..." : "Salvar";
41869
+ }
41870
+ if (cancelBtn) {
41871
+ cancelBtn.disabled = isLoading;
41872
+ }
41873
+ formInputs.forEach((input) => {
41874
+ input.disabled = isLoading;
41875
+ });
41876
+ }
41877
+ getFormData() {
41878
+ const getValue = (name) => {
41879
+ const input = this.form.querySelector(`[name="${name}"]`);
41880
+ if (!input || input.value === "") return null;
41881
+ const num = parseInt(input.value, 10);
41882
+ return isNaN(num) ? null : num;
41883
+ };
41884
+ return {
41885
+ energy: {
41886
+ total: getValue("energy_total"),
41887
+ entries: getValue("energy_entries"),
41888
+ commonArea: getValue("energy_commonArea"),
41889
+ stores: getValue("energy_stores")
41890
+ },
41891
+ water: {
41892
+ total: getValue("water_total"),
41893
+ entries: getValue("water_entries"),
41894
+ commonArea: getValue("water_commonArea"),
41895
+ stores: getValue("water_stores")
41896
+ },
41897
+ temperature: {
41898
+ total: getValue("temperature_total"),
41899
+ internal: getValue("temperature_internal"),
41900
+ stores: getValue("temperature_stores")
41901
+ }
41902
+ };
41903
+ }
41904
+ createModal() {
41905
+ this.container = document.createElement("div");
41906
+ this.container.className = "myio-contract-devices-modal-overlay";
41907
+ this.container.innerHTML = this.getModalHTML();
41908
+ this.modal = this.container.querySelector(".myio-contract-devices-modal");
41909
+ this.form = this.modal.querySelector("form");
41910
+ }
41911
+ getModalHTML() {
41912
+ const width = typeof this.config.width === "number" ? `${this.config.width}px` : this.config.width;
41913
+ return `
41914
+ <div class="myio-contract-devices-modal-overlay" role="dialog" aria-modal="true" aria-labelledby="modal-title">
41915
+ <div class="myio-contract-devices-modal" style="width: ${width}">
41916
+ <div class="modal-header">
41917
+ <h3 id="modal-title">${this.config.title || "Configurar Dispositivos Contratados"}</h3>
41918
+ <button type="button" class="close-btn" aria-label="Fechar">&times;</button>
41919
+ </div>
41920
+ <div class="modal-body">
41921
+ <div class="error-message" style="display: none;" role="alert"></div>
41922
+ ${this.config.customerName ? `
41923
+ <div class="customer-info">
41924
+ <span class="customer-label">Shopping:</span>
41925
+ <span class="customer-name">${this.config.customerName}</span>
41926
+ </div>
41927
+ ` : ""}
41928
+ <form novalidate>
41929
+ ${this.getFormHTML()}
41930
+ </form>
41931
+ </div>
41932
+ <div class="modal-footer">
41933
+ <button type="button" class="btn-cancel">Fechar</button>
41934
+ <button type="button" class="btn-save btn-primary">Salvar</button>
41935
+ </div>
41936
+ </div>
41937
+ </div>
41938
+ ${this.getModalCSS()}
41939
+ `;
41940
+ }
41941
+ getFormHTML() {
41942
+ return `
41943
+ <div class="form-layout">
41944
+ <!-- Energy Section -->
41945
+ <div class="domain-card energy-card">
41946
+ <div class="domain-header">
41947
+ <span class="domain-icon">&#9889;</span>
41948
+ <h4>Energia</h4>
41949
+ </div>
41950
+ <div class="domain-fields">
41951
+ <div class="field-group">
41952
+ <label for="energy_total">Total Contratado</label>
41953
+ <input type="number" id="energy_total" name="energy_total" min="0" step="1" placeholder="0">
41954
+ <small class="field-key">${DEVICE_COUNT_KEYS.energy.total}</small>
41955
+ </div>
41956
+ <div class="field-group">
41957
+ <label for="energy_entries">Entradas</label>
41958
+ <input type="number" id="energy_entries" name="energy_entries" min="0" step="1" placeholder="0">
41959
+ <small class="field-key">${DEVICE_COUNT_KEYS.energy.entries}</small>
41960
+ </div>
41961
+ <div class="field-group">
41962
+ <label for="energy_commonArea">Area Comum</label>
41963
+ <input type="number" id="energy_commonArea" name="energy_commonArea" min="0" step="1" placeholder="0">
41964
+ <small class="field-key">${DEVICE_COUNT_KEYS.energy.commonArea}</small>
41965
+ </div>
41966
+ <div class="field-group">
41967
+ <label for="energy_stores">Lojas</label>
41968
+ <input type="number" id="energy_stores" name="energy_stores" min="0" step="1" placeholder="0">
41969
+ <small class="field-key">${DEVICE_COUNT_KEYS.energy.stores}</small>
41970
+ </div>
41971
+ </div>
41972
+ </div>
41973
+
41974
+ <!-- Water Section -->
41975
+ <div class="domain-card water-card">
41976
+ <div class="domain-header">
41977
+ <span class="domain-icon">&#128167;</span>
41978
+ <h4>Agua</h4>
41979
+ </div>
41980
+ <div class="domain-fields">
41981
+ <div class="field-group">
41982
+ <label for="water_total">Total Contratado</label>
41983
+ <input type="number" id="water_total" name="water_total" min="0" step="1" placeholder="0">
41984
+ <small class="field-key">${DEVICE_COUNT_KEYS.water.total}</small>
41985
+ </div>
41986
+ <div class="field-group">
41987
+ <label for="water_entries">Entradas</label>
41988
+ <input type="number" id="water_entries" name="water_entries" min="0" step="1" placeholder="0">
41989
+ <small class="field-key">${DEVICE_COUNT_KEYS.water.entries}</small>
41990
+ </div>
41991
+ <div class="field-group">
41992
+ <label for="water_commonArea">Area Comum</label>
41993
+ <input type="number" id="water_commonArea" name="water_commonArea" min="0" step="1" placeholder="0">
41994
+ <small class="field-key">${DEVICE_COUNT_KEYS.water.commonArea}</small>
41995
+ </div>
41996
+ <div class="field-group">
41997
+ <label for="water_stores">Lojas</label>
41998
+ <input type="number" id="water_stores" name="water_stores" min="0" step="1" placeholder="0">
41999
+ <small class="field-key">${DEVICE_COUNT_KEYS.water.stores}</small>
42000
+ </div>
42001
+ </div>
42002
+ </div>
42003
+
42004
+ <!-- Temperature Section -->
42005
+ <div class="domain-card temperature-card">
42006
+ <div class="domain-header">
42007
+ <span class="domain-icon">&#127777;</span>
42008
+ <h4>Temperatura</h4>
42009
+ </div>
42010
+ <div class="domain-fields">
42011
+ <div class="field-group">
42012
+ <label for="temperature_total">Total Contratado</label>
42013
+ <input type="number" id="temperature_total" name="temperature_total" min="0" step="1" placeholder="0">
42014
+ <small class="field-key">${DEVICE_COUNT_KEYS.temperature.total}</small>
42015
+ </div>
42016
+ <div class="field-group">
42017
+ <label for="temperature_internal">Sensores Internos</label>
42018
+ <input type="number" id="temperature_internal" name="temperature_internal" min="0" step="1" placeholder="0">
42019
+ <small class="field-key">${DEVICE_COUNT_KEYS.temperature.internal}</small>
42020
+ </div>
42021
+ <div class="field-group">
42022
+ <label for="temperature_stores">Lojas</label>
42023
+ <input type="number" id="temperature_stores" name="temperature_stores" min="0" step="1" placeholder="0">
42024
+ <small class="field-key">${DEVICE_COUNT_KEYS.temperature.stores}</small>
42025
+ </div>
42026
+ </div>
42027
+ </div>
42028
+ </div>
42029
+ `;
42030
+ }
42031
+ getModalCSS() {
42032
+ return `
42033
+ <style>
42034
+ .myio-contract-devices-modal-overlay {
42035
+ position: fixed;
42036
+ top: 0;
42037
+ left: 0;
42038
+ right: 0;
42039
+ bottom: 0;
42040
+ background: rgba(0, 0, 0, 0.5);
42041
+ display: flex;
42042
+ align-items: center;
42043
+ justify-content: center;
42044
+ z-index: 10000;
42045
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
42046
+ }
42047
+
42048
+ .myio-contract-devices-modal {
42049
+ background: white;
42050
+ border-radius: 12px;
42051
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.25);
42052
+ max-width: 95vw;
42053
+ max-height: 90vh;
42054
+ width: 800px;
42055
+ overflow: hidden;
42056
+ display: flex;
42057
+ flex-direction: column;
42058
+ }
42059
+
42060
+ .myio-contract-devices-modal .modal-header {
42061
+ background: linear-gradient(135deg, #3e1a7d 0%, #5c2d91 100%);
42062
+ color: white;
42063
+ padding: 20px 24px;
42064
+ display: flex;
42065
+ justify-content: space-between;
42066
+ align-items: center;
42067
+ }
42068
+
42069
+ .myio-contract-devices-modal .modal-header h3 {
42070
+ margin: 0;
42071
+ font-size: 18px;
42072
+ font-weight: 600;
42073
+ color: white;
42074
+ }
42075
+
42076
+ .myio-contract-devices-modal .close-btn {
42077
+ background: none;
42078
+ border: none;
42079
+ font-size: 24px;
42080
+ cursor: pointer;
42081
+ color: white;
42082
+ padding: 0;
42083
+ width: 32px;
42084
+ height: 32px;
42085
+ display: flex;
42086
+ align-items: center;
42087
+ justify-content: center;
42088
+ border-radius: 4px;
42089
+ transition: background 0.2s;
42090
+ }
42091
+
42092
+ .myio-contract-devices-modal .close-btn:hover {
42093
+ background: rgba(255, 255, 255, 0.1);
42094
+ }
42095
+
42096
+ .myio-contract-devices-modal .modal-body {
42097
+ padding: 24px;
42098
+ overflow-y: auto;
42099
+ flex: 1;
42100
+ background: #f8f9fa;
42101
+ }
42102
+
42103
+ .myio-contract-devices-modal .error-message {
42104
+ background: #fee;
42105
+ border: 1px solid #fcc;
42106
+ color: #c33;
42107
+ padding: 12px;
42108
+ border-radius: 6px;
42109
+ margin-bottom: 16px;
42110
+ font-size: 14px;
42111
+ }
42112
+
42113
+ .myio-contract-devices-modal .customer-info {
42114
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
42115
+ padding: 16px 20px;
42116
+ border-radius: 8px;
42117
+ margin-bottom: 20px;
42118
+ display: flex;
42119
+ align-items: center;
42120
+ gap: 10px;
42121
+ }
42122
+
42123
+ .myio-contract-devices-modal .customer-label {
42124
+ color: rgba(255, 255, 255, 0.8);
42125
+ font-size: 13px;
42126
+ font-weight: 500;
42127
+ }
42128
+
42129
+ .myio-contract-devices-modal .customer-name {
42130
+ color: white;
42131
+ font-size: 16px;
42132
+ font-weight: 600;
42133
+ }
42134
+
42135
+ .myio-contract-devices-modal .form-layout {
42136
+ display: grid;
42137
+ grid-template-columns: repeat(3, 1fr);
42138
+ gap: 20px;
42139
+ }
42140
+
42141
+ .myio-contract-devices-modal .domain-card {
42142
+ background: white;
42143
+ border-radius: 10px;
42144
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
42145
+ overflow: hidden;
42146
+ }
42147
+
42148
+ .myio-contract-devices-modal .domain-header {
42149
+ padding: 14px 16px;
42150
+ display: flex;
42151
+ align-items: center;
42152
+ gap: 10px;
42153
+ border-bottom: 1px solid #eee;
42154
+ }
42155
+
42156
+ .myio-contract-devices-modal .domain-header h4 {
42157
+ margin: 0;
42158
+ font-size: 15px;
42159
+ font-weight: 600;
42160
+ color: #333;
42161
+ }
42162
+
42163
+ .myio-contract-devices-modal .domain-icon {
42164
+ font-size: 20px;
42165
+ }
42166
+
42167
+ .myio-contract-devices-modal .energy-card .domain-header {
42168
+ background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
42169
+ }
42170
+
42171
+ .myio-contract-devices-modal .water-card .domain-header {
42172
+ background: linear-gradient(135deg, #dbeafe 0%, #93c5fd 100%);
42173
+ }
42174
+
42175
+ .myio-contract-devices-modal .temperature-card .domain-header {
42176
+ background: linear-gradient(135deg, #fce7f3 0%, #f9a8d4 100%);
42177
+ }
42178
+
42179
+ .myio-contract-devices-modal .domain-fields {
42180
+ padding: 16px;
42181
+ display: flex;
42182
+ flex-direction: column;
42183
+ gap: 14px;
42184
+ }
42185
+
42186
+ .myio-contract-devices-modal .field-group {
42187
+ display: flex;
42188
+ flex-direction: column;
42189
+ gap: 4px;
42190
+ }
42191
+
42192
+ .myio-contract-devices-modal .field-group label {
42193
+ font-size: 13px;
42194
+ font-weight: 500;
42195
+ color: #555;
42196
+ }
42197
+
42198
+ .myio-contract-devices-modal .field-group input {
42199
+ width: 100%;
42200
+ padding: 10px 12px;
42201
+ border: 1px solid #ddd;
42202
+ border-radius: 6px;
42203
+ font-size: 14px;
42204
+ transition: border-color 0.2s, box-shadow 0.2s;
42205
+ box-sizing: border-box;
42206
+ }
42207
+
42208
+ .myio-contract-devices-modal .field-group input:focus {
42209
+ outline: none;
42210
+ border-color: #3e1a7d;
42211
+ box-shadow: 0 0 0 3px rgba(62, 26, 125, 0.15);
42212
+ }
42213
+
42214
+ .myio-contract-devices-modal .field-key {
42215
+ font-size: 10px;
42216
+ color: #999;
42217
+ font-family: 'Courier New', monospace;
42218
+ }
42219
+
42220
+ .myio-contract-devices-modal .modal-footer {
42221
+ padding: 16px 24px;
42222
+ border-top: 1px solid #e0e0e0;
42223
+ display: flex;
42224
+ justify-content: flex-end;
42225
+ gap: 12px;
42226
+ background: white;
42227
+ }
42228
+
42229
+ .myio-contract-devices-modal .modal-footer button {
42230
+ padding: 10px 24px;
42231
+ border: none;
42232
+ border-radius: 6px;
42233
+ font-size: 14px;
42234
+ font-weight: 500;
42235
+ cursor: pointer;
42236
+ transition: all 0.2s;
42237
+ }
42238
+
42239
+ .myio-contract-devices-modal .btn-cancel {
42240
+ background: #6c757d;
42241
+ color: white;
42242
+ }
42243
+
42244
+ .myio-contract-devices-modal .btn-cancel:hover:not(:disabled) {
42245
+ background: #545b62;
42246
+ }
42247
+
42248
+ .myio-contract-devices-modal .btn-primary {
42249
+ background: #3e1a7d;
42250
+ color: white;
42251
+ }
42252
+
42253
+ .myio-contract-devices-modal .btn-primary:hover:not(:disabled) {
42254
+ background: #2d1458;
42255
+ }
42256
+
42257
+ .myio-contract-devices-modal .modal-footer button:disabled {
42258
+ opacity: 0.6;
42259
+ cursor: not-allowed;
42260
+ }
42261
+
42262
+ /* Responsive */
42263
+ @media (max-width: 900px) {
42264
+ .myio-contract-devices-modal .form-layout {
42265
+ grid-template-columns: 1fr;
42266
+ }
42267
+
42268
+ .myio-contract-devices-modal {
42269
+ width: 95vw !important;
42270
+ }
42271
+ }
42272
+
42273
+ /* Scrollbar */
42274
+ .myio-contract-devices-modal .modal-body::-webkit-scrollbar {
42275
+ width: 6px;
42276
+ }
42277
+
42278
+ .myio-contract-devices-modal .modal-body::-webkit-scrollbar-track {
42279
+ background: #f1f1f1;
42280
+ border-radius: 3px;
42281
+ }
42282
+
42283
+ .myio-contract-devices-modal .modal-body::-webkit-scrollbar-thumb {
42284
+ background: #c1c1c1;
42285
+ border-radius: 3px;
42286
+ }
42287
+ </style>
42288
+ `;
42289
+ }
42290
+ populateForm(data) {
42291
+ const setValue = (name, value) => {
42292
+ const input = this.form.querySelector(`[name="${name}"]`);
42293
+ if (input && value !== null && value !== void 0) {
42294
+ input.value = String(value);
42295
+ }
42296
+ };
42297
+ if (data.energy) {
42298
+ setValue("energy_total", data.energy.total);
42299
+ setValue("energy_entries", data.energy.entries);
42300
+ setValue("energy_commonArea", data.energy.commonArea);
42301
+ setValue("energy_stores", data.energy.stores);
42302
+ }
42303
+ if (data.water) {
42304
+ setValue("water_total", data.water.total);
42305
+ setValue("water_entries", data.water.entries);
42306
+ setValue("water_commonArea", data.water.commonArea);
42307
+ setValue("water_stores", data.water.stores);
42308
+ }
42309
+ if (data.temperature) {
42310
+ setValue("temperature_total", data.temperature.total);
42311
+ setValue("temperature_internal", data.temperature.internal);
42312
+ setValue("temperature_stores", data.temperature.stores);
42313
+ }
42314
+ }
42315
+ attachEventListeners() {
42316
+ const closeBtn = this.modal.querySelector(".close-btn");
42317
+ if (closeBtn) {
42318
+ closeBtn.addEventListener("click", (e) => {
42319
+ e.preventDefault();
42320
+ this.config.onClose();
42321
+ });
42322
+ }
42323
+ const cancelBtn = this.modal.querySelector(".btn-cancel");
42324
+ if (cancelBtn) {
42325
+ cancelBtn.addEventListener("click", (e) => {
42326
+ e.preventDefault();
42327
+ this.config.onClose();
42328
+ });
42329
+ }
42330
+ const saveBtn = this.modal.querySelector(".btn-save");
42331
+ if (saveBtn) {
42332
+ saveBtn.addEventListener("click", async (e) => {
42333
+ e.preventDefault();
42334
+ this.hideError();
42335
+ const formData = this.getFormData();
42336
+ await this.config.onSave(formData);
42337
+ });
42338
+ }
42339
+ this.container.addEventListener("click", (e) => {
42340
+ const target = e.target;
42341
+ if (target.classList.contains("myio-contract-devices-modal-overlay") && this.config.closeOnBackdrop !== false) {
42342
+ this.config.onClose();
42343
+ }
42344
+ });
42345
+ }
42346
+ setupAccessibility() {
42347
+ const firstInput = this.modal.querySelector("input");
42348
+ if (firstInput) {
42349
+ setTimeout(() => firstInput.focus(), 100);
42350
+ }
42351
+ this.modal.setAttribute("aria-labelledby", "modal-title");
42352
+ }
42353
+ setupFocusTrap() {
42354
+ this.focusTrapElements = Array.from(
42355
+ this.modal.querySelectorAll('button, input, [tabindex]:not([tabindex="-1"])')
42356
+ );
42357
+ this.modal.addEventListener("keydown", this.handleKeyDown.bind(this));
42358
+ }
42359
+ teardownFocusTrap() {
42360
+ this.modal.removeEventListener("keydown", this.handleKeyDown.bind(this));
42361
+ }
42362
+ handleKeyDown(event) {
42363
+ if (event.key === "Escape" && this.config.closeOnBackdrop !== false) {
42364
+ event.preventDefault();
42365
+ this.config.onClose();
42366
+ return;
42367
+ }
42368
+ if (event.key === "Tab") {
42369
+ const firstElement = this.focusTrapElements[0];
42370
+ const lastElement = this.focusTrapElements[this.focusTrapElements.length - 1];
42371
+ if (event.shiftKey) {
42372
+ if (document.activeElement === firstElement) {
42373
+ event.preventDefault();
42374
+ lastElement.focus();
42375
+ }
42376
+ } else {
42377
+ if (document.activeElement === lastElement) {
42378
+ event.preventDefault();
42379
+ firstElement.focus();
42380
+ }
42381
+ }
42382
+ }
42383
+ }
42384
+ };
42385
+
42386
+ // src/components/premium-modals/contract-devices/ContractDevicesPersister.ts
42387
+ var DefaultContractDevicesPersister = class {
42388
+ jwtToken;
42389
+ tbBaseUrl;
42390
+ constructor(jwtToken, apiConfig) {
42391
+ this.jwtToken = jwtToken;
42392
+ this.tbBaseUrl = apiConfig?.tbBaseUrl || window.location.origin;
42393
+ }
42394
+ async saveDeviceCounts(customerId, counts) {
42395
+ try {
42396
+ const payload = {};
42397
+ if (counts.energy.total !== null) {
42398
+ payload[DEVICE_COUNT_KEYS.energy.total] = counts.energy.total;
42399
+ }
42400
+ if (counts.energy.entries !== null) {
42401
+ payload[DEVICE_COUNT_KEYS.energy.entries] = counts.energy.entries;
42402
+ }
42403
+ if (counts.energy.commonArea !== null) {
42404
+ payload[DEVICE_COUNT_KEYS.energy.commonArea] = counts.energy.commonArea;
42405
+ }
42406
+ if (counts.energy.stores !== null) {
42407
+ payload[DEVICE_COUNT_KEYS.energy.stores] = counts.energy.stores;
42408
+ }
42409
+ if (counts.water.total !== null) {
42410
+ payload[DEVICE_COUNT_KEYS.water.total] = counts.water.total;
42411
+ }
42412
+ if (counts.water.entries !== null) {
42413
+ payload[DEVICE_COUNT_KEYS.water.entries] = counts.water.entries;
42414
+ }
42415
+ if (counts.water.commonArea !== null) {
42416
+ payload[DEVICE_COUNT_KEYS.water.commonArea] = counts.water.commonArea;
42417
+ }
42418
+ if (counts.water.stores !== null) {
42419
+ payload[DEVICE_COUNT_KEYS.water.stores] = counts.water.stores;
42420
+ }
42421
+ if (counts.temperature.total !== null) {
42422
+ payload[DEVICE_COUNT_KEYS.temperature.total] = counts.temperature.total;
42423
+ }
42424
+ if (counts.temperature.internal !== null) {
42425
+ payload[DEVICE_COUNT_KEYS.temperature.internal] = counts.temperature.internal;
42426
+ }
42427
+ if (counts.temperature.stores !== null) {
42428
+ payload[DEVICE_COUNT_KEYS.temperature.stores] = counts.temperature.stores;
42429
+ }
42430
+ console.log("[ContractDevicesPersister] Saving to CUSTOMER SERVER_SCOPE:", payload);
42431
+ const res = await fetch(
42432
+ `${this.tbBaseUrl}/api/plugins/telemetry/CUSTOMER/${customerId}/attributes/SERVER_SCOPE`,
42433
+ {
42434
+ method: "POST",
42435
+ headers: {
42436
+ "X-Authorization": `Bearer ${this.jwtToken}`,
42437
+ "Content-Type": "application/json"
42438
+ },
42439
+ body: JSON.stringify(payload)
42440
+ }
42441
+ );
42442
+ if (!res.ok) {
42443
+ throw this.createHttpError(res.status, await res.text().catch(() => ""));
42444
+ }
42445
+ return {
42446
+ ok: true,
42447
+ updatedKeys: Object.keys(payload),
42448
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
42449
+ };
42450
+ } catch (error) {
42451
+ console.error("[ContractDevicesPersister] Save failed:", error);
42452
+ return {
42453
+ ok: false,
42454
+ error: this.mapError(error)
42455
+ };
42456
+ }
42457
+ }
42458
+ createHttpError(status, body) {
42459
+ const error = new Error(`HTTP ${status}: ${body}`);
42460
+ error.status = status;
42461
+ error.body = body;
42462
+ return error;
42463
+ }
42464
+ mapError(error) {
42465
+ const status = error.status;
42466
+ if (status === 400) {
42467
+ return {
42468
+ code: "VALIDATION_ERROR",
42469
+ message: "Dados invalidos",
42470
+ userAction: "FIX_INPUT",
42471
+ cause: error
42472
+ };
42473
+ }
42474
+ if (status === 401) {
42475
+ return {
42476
+ code: "TOKEN_EXPIRED",
42477
+ message: "Token de autenticacao expirado",
42478
+ userAction: "RE_AUTH",
42479
+ cause: error
42480
+ };
42481
+ }
42482
+ if (status === 403) {
42483
+ return {
42484
+ code: "AUTH_ERROR",
42485
+ message: "Permissao insuficiente",
42486
+ userAction: "RE_AUTH",
42487
+ cause: error
42488
+ };
42489
+ }
42490
+ if (status === 404) {
42491
+ return {
42492
+ code: "NETWORK_ERROR",
42493
+ message: "Cliente nao encontrado",
42494
+ userAction: "CONTACT_ADMIN",
42495
+ cause: error
42496
+ };
42497
+ }
42498
+ if (status >= 500) {
42499
+ return {
42500
+ code: "NETWORK_ERROR",
42501
+ message: "Erro no servidor",
42502
+ userAction: "RETRY",
42503
+ cause: error
42504
+ };
42505
+ }
42506
+ return {
42507
+ code: "UNKNOWN_ERROR",
42508
+ message: error.message || "Erro desconhecido",
42509
+ userAction: "CONTACT_ADMIN",
42510
+ cause: error
42511
+ };
42512
+ }
42513
+ };
42514
+
42515
+ // src/components/premium-modals/contract-devices/ContractDevicesFetcher.ts
42516
+ var DefaultContractDevicesFetcher = class {
42517
+ jwtToken;
42518
+ tbBaseUrl;
42519
+ constructor(jwtToken, apiConfig) {
42520
+ this.jwtToken = jwtToken;
42521
+ this.tbBaseUrl = apiConfig?.tbBaseUrl || window.location.origin;
42522
+ }
42523
+ async fetchCurrentCounts(customerId) {
42524
+ try {
42525
+ const keys = [
42526
+ DEVICE_COUNT_KEYS.energy.total,
42527
+ DEVICE_COUNT_KEYS.energy.entries,
42528
+ DEVICE_COUNT_KEYS.energy.commonArea,
42529
+ DEVICE_COUNT_KEYS.energy.stores,
42530
+ DEVICE_COUNT_KEYS.water.total,
42531
+ DEVICE_COUNT_KEYS.water.entries,
42532
+ DEVICE_COUNT_KEYS.water.commonArea,
42533
+ DEVICE_COUNT_KEYS.water.stores,
42534
+ DEVICE_COUNT_KEYS.temperature.total,
42535
+ DEVICE_COUNT_KEYS.temperature.internal,
42536
+ DEVICE_COUNT_KEYS.temperature.stores
42537
+ ];
42538
+ const url = `${this.tbBaseUrl}/api/plugins/telemetry/CUSTOMER/${customerId}/values/attributes/SERVER_SCOPE?keys=${keys.join(",")}`;
42539
+ console.log("[ContractDevicesFetcher] Fetching from:", url);
42540
+ const res = await fetch(url, {
42541
+ headers: {
42542
+ "X-Authorization": `Bearer ${this.jwtToken}`,
42543
+ "Content-Type": "application/json"
42544
+ }
42545
+ });
42546
+ if (!res.ok) {
42547
+ console.warn("[ContractDevicesFetcher] Fetch failed:", res.status);
42548
+ return {};
42549
+ }
42550
+ const data = await res.json();
42551
+ console.log("[ContractDevicesFetcher] Received data:", data);
42552
+ return this.parseAttributesToCounts(data);
42553
+ } catch (error) {
42554
+ console.error("[ContractDevicesFetcher] Error fetching counts:", error);
42555
+ return {};
42556
+ }
42557
+ }
42558
+ parseAttributesToCounts(attributes) {
42559
+ const getValue = (key) => {
42560
+ const attr = attributes.find((a) => a.key === key);
42561
+ if (!attr) return null;
42562
+ const num = parseInt(attr.value, 10);
42563
+ return isNaN(num) ? null : num;
42564
+ };
42565
+ return {
42566
+ energy: {
42567
+ total: getValue(DEVICE_COUNT_KEYS.energy.total),
42568
+ entries: getValue(DEVICE_COUNT_KEYS.energy.entries),
42569
+ commonArea: getValue(DEVICE_COUNT_KEYS.energy.commonArea),
42570
+ stores: getValue(DEVICE_COUNT_KEYS.energy.stores)
42571
+ },
42572
+ water: {
42573
+ total: getValue(DEVICE_COUNT_KEYS.water.total),
42574
+ entries: getValue(DEVICE_COUNT_KEYS.water.entries),
42575
+ commonArea: getValue(DEVICE_COUNT_KEYS.water.commonArea),
42576
+ stores: getValue(DEVICE_COUNT_KEYS.water.stores)
42577
+ },
42578
+ temperature: {
42579
+ total: getValue(DEVICE_COUNT_KEYS.temperature.total),
42580
+ internal: getValue(DEVICE_COUNT_KEYS.temperature.internal),
42581
+ stores: getValue(DEVICE_COUNT_KEYS.temperature.stores)
42582
+ }
42583
+ };
42584
+ }
42585
+ };
42586
+
42587
+ // src/components/premium-modals/contract-devices/ContractDevicesController.ts
42588
+ var ContractDevicesController = class {
42589
+ params;
42590
+ view = null;
42591
+ persister;
42592
+ fetcher;
42593
+ constructor(params) {
42594
+ this.params = params;
42595
+ this.persister = new DefaultContractDevicesPersister(
42596
+ params.jwtToken,
42597
+ params.api
42598
+ );
42599
+ this.fetcher = new DefaultContractDevicesFetcher(
42600
+ params.jwtToken,
42601
+ params.api
42602
+ );
42603
+ }
42604
+ async show() {
42605
+ let seedData = this.params.seed || {};
42606
+ try {
42607
+ const existingCounts = await this.fetcher.fetchCurrentCounts(this.params.customerId);
42608
+ seedData = this.mergeCounts(seedData, existingCounts);
42609
+ console.log("[ContractDevicesController] Merged seed data:", seedData);
42610
+ } catch (error) {
42611
+ console.warn("[ContractDevicesController] Failed to fetch existing counts:", error);
42612
+ }
42613
+ const viewConfig = {
42614
+ title: this.params.ui?.title || "Configurar Dispositivos Contratados",
42615
+ width: this.params.ui?.width || 800,
42616
+ closeOnBackdrop: this.params.ui?.closeOnBackdrop !== false,
42617
+ customerName: this.params.customerName,
42618
+ onSave: this.handleSave.bind(this),
42619
+ onClose: this.handleClose.bind(this)
42620
+ };
42621
+ this.view = new ContractDevicesModalView(viewConfig);
42622
+ this.view.render(seedData);
42623
+ }
42624
+ async handleSave(formData) {
42625
+ if (!this.view) return;
42626
+ this.view.showLoadingState(true);
42627
+ this.view.hideError();
42628
+ try {
42629
+ const result = await this.persister.saveDeviceCounts(
42630
+ this.params.customerId,
42631
+ formData
42632
+ );
42633
+ if (result.ok) {
42634
+ console.log("[ContractDevicesController] Save successful:", result);
42635
+ if (this.params.onSaved) {
42636
+ this.params.onSaved(result);
42637
+ }
42638
+ this.handleClose();
42639
+ } else {
42640
+ console.error("[ContractDevicesController] Save failed:", result.error);
42641
+ this.view.showError(result.error?.message || "Erro ao salvar configuracoes");
42642
+ if (this.params.onError && result.error) {
42643
+ this.params.onError(result.error);
42644
+ }
42645
+ }
42646
+ } catch (error) {
42647
+ console.error("[ContractDevicesController] Unexpected error:", error);
42648
+ this.view.showError(error.message || "Erro inesperado");
42649
+ if (this.params.onError) {
42650
+ this.params.onError({
42651
+ code: "UNKNOWN_ERROR",
42652
+ message: error.message || "Erro desconhecido",
42653
+ cause: error
42654
+ });
42655
+ }
42656
+ } finally {
42657
+ if (this.view) {
42658
+ this.view.showLoadingState(false);
42659
+ }
42660
+ }
42661
+ }
42662
+ handleClose() {
42663
+ if (this.view) {
42664
+ this.view.close();
42665
+ this.view = null;
42666
+ }
42667
+ if (this.params.onClose) {
42668
+ this.params.onClose();
42669
+ }
42670
+ }
42671
+ mergeCounts(seed, fetched) {
42672
+ return {
42673
+ energy: {
42674
+ total: fetched.energy?.total ?? seed.energy?.total ?? null,
42675
+ entries: fetched.energy?.entries ?? seed.energy?.entries ?? null,
42676
+ commonArea: fetched.energy?.commonArea ?? seed.energy?.commonArea ?? null,
42677
+ stores: fetched.energy?.stores ?? seed.energy?.stores ?? null
42678
+ },
42679
+ water: {
42680
+ total: fetched.water?.total ?? seed.water?.total ?? null,
42681
+ entries: fetched.water?.entries ?? seed.water?.entries ?? null,
42682
+ commonArea: fetched.water?.commonArea ?? seed.water?.commonArea ?? null,
42683
+ stores: fetched.water?.stores ?? seed.water?.stores ?? null
42684
+ },
42685
+ temperature: {
42686
+ total: fetched.temperature?.total ?? seed.temperature?.total ?? null,
42687
+ internal: fetched.temperature?.internal ?? seed.temperature?.internal ?? null,
42688
+ stores: fetched.temperature?.stores ?? seed.temperature?.stores ?? null
42689
+ }
42690
+ };
42691
+ }
42692
+ };
42693
+
42694
+ // src/components/premium-modals/contract-devices/openContractDevicesModal.ts
42695
+ async function openContractDevicesModal(params) {
42696
+ if (!params.jwtToken) {
42697
+ throw new Error("jwtToken is required for contract devices persistence");
42698
+ }
42699
+ if (!params.customerId) {
42700
+ throw new Error("customerId is required");
42701
+ }
42702
+ console.info("[openContractDevicesModal] Initializing contract devices modal", {
42703
+ customerId: params.customerId,
42704
+ customerName: params.customerName,
42705
+ hasJwtToken: !!params.jwtToken,
42706
+ hasSeedData: !!params.seed
42707
+ });
42708
+ const controller = new ContractDevicesController(params);
42709
+ try {
42710
+ await controller.show();
42711
+ } catch (error) {
42712
+ console.error("[openContractDevicesModal] Error:", error);
42713
+ if (params.onError) {
42714
+ params.onError({
42715
+ code: "UNKNOWN_ERROR",
42716
+ message: error.message || "Erro ao abrir modal de dispositivos contratados",
42717
+ cause: error
42718
+ });
42719
+ }
42720
+ throw error;
42721
+ }
42722
+ }
42723
+
41798
42724
  exports.ANNOTATION_TYPE_COLORS = ANNOTATION_TYPE_COLORS;
41799
42725
  exports.ANNOTATION_TYPE_LABELS = ANNOTATION_TYPE_LABELS;
41800
42726
  exports.ANNOTATION_TYPE_LABELS_EN = ANNOTATION_TYPE_LABELS_EN;
@@ -41810,6 +42736,7 @@
41810
42736
  exports.DEFAULT_GAS_GROUP_COLORS = DEFAULT_GAS_GROUP_COLORS;
41811
42737
  exports.DEFAULT_SHOPPING_COLORS = DEFAULT_SHOPPING_COLORS;
41812
42738
  exports.DEFAULT_WATER_GROUP_COLORS = DEFAULT_WATER_GROUP_COLORS;
42739
+ exports.DEVICE_COUNT_KEYS = DEVICE_COUNT_KEYS;
41813
42740
  exports.DeviceComparisonTooltip = DeviceComparisonTooltip;
41814
42741
  exports.DeviceStatusType = DeviceStatusType;
41815
42742
  exports.EXPORT_DEFAULT_COLORS = EXPORT_DEFAULT_COLORS;
@@ -41931,6 +42858,7 @@
41931
42858
  exports.myioExportData = myioExportData;
41932
42859
  exports.normalizeRecipients = normalizeRecipients;
41933
42860
  exports.numbers = numbers_exports;
42861
+ exports.openContractDevicesModal = openContractDevicesModal;
41934
42862
  exports.openDashboardPopup = openDashboardPopup;
41935
42863
  exports.openDashboardPopupAllReport = openDashboardPopupAllReport;
41936
42864
  exports.openDashboardPopupEnergy = openDashboardPopupEnergy;