myio-js-library 0.1.200 → 0.1.202

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -41795,6 +41795,965 @@
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
+ white-space: pre-line;
42112
+ line-height: 1.6;
42113
+ }
42114
+
42115
+ .myio-contract-devices-modal .customer-info {
42116
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
42117
+ padding: 16px 20px;
42118
+ border-radius: 8px;
42119
+ margin-bottom: 20px;
42120
+ display: flex;
42121
+ align-items: center;
42122
+ gap: 10px;
42123
+ }
42124
+
42125
+ .myio-contract-devices-modal .customer-label {
42126
+ color: rgba(255, 255, 255, 0.8);
42127
+ font-size: 13px;
42128
+ font-weight: 500;
42129
+ }
42130
+
42131
+ .myio-contract-devices-modal .customer-name {
42132
+ color: white;
42133
+ font-size: 16px;
42134
+ font-weight: 600;
42135
+ }
42136
+
42137
+ .myio-contract-devices-modal .form-layout {
42138
+ display: grid;
42139
+ grid-template-columns: repeat(3, 1fr);
42140
+ gap: 20px;
42141
+ }
42142
+
42143
+ .myio-contract-devices-modal .domain-card {
42144
+ background: white;
42145
+ border-radius: 10px;
42146
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
42147
+ overflow: hidden;
42148
+ }
42149
+
42150
+ .myio-contract-devices-modal .domain-header {
42151
+ padding: 14px 16px;
42152
+ display: flex;
42153
+ align-items: center;
42154
+ gap: 10px;
42155
+ border-bottom: 1px solid #eee;
42156
+ }
42157
+
42158
+ .myio-contract-devices-modal .domain-header h4 {
42159
+ margin: 0;
42160
+ font-size: 15px;
42161
+ font-weight: 600;
42162
+ color: #333;
42163
+ }
42164
+
42165
+ .myio-contract-devices-modal .domain-icon {
42166
+ font-size: 20px;
42167
+ }
42168
+
42169
+ .myio-contract-devices-modal .energy-card .domain-header {
42170
+ background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
42171
+ }
42172
+
42173
+ .myio-contract-devices-modal .water-card .domain-header {
42174
+ background: linear-gradient(135deg, #dbeafe 0%, #93c5fd 100%);
42175
+ }
42176
+
42177
+ .myio-contract-devices-modal .temperature-card .domain-header {
42178
+ background: linear-gradient(135deg, #fce7f3 0%, #f9a8d4 100%);
42179
+ }
42180
+
42181
+ .myio-contract-devices-modal .domain-fields {
42182
+ padding: 16px;
42183
+ display: flex;
42184
+ flex-direction: column;
42185
+ gap: 14px;
42186
+ }
42187
+
42188
+ .myio-contract-devices-modal .field-group {
42189
+ display: flex;
42190
+ flex-direction: column;
42191
+ gap: 4px;
42192
+ }
42193
+
42194
+ .myio-contract-devices-modal .field-group label {
42195
+ font-size: 13px;
42196
+ font-weight: 500;
42197
+ color: #555;
42198
+ }
42199
+
42200
+ .myio-contract-devices-modal .field-group input {
42201
+ width: 100%;
42202
+ padding: 10px 12px;
42203
+ border: 1px solid #ddd;
42204
+ border-radius: 6px;
42205
+ font-size: 14px;
42206
+ transition: border-color 0.2s, box-shadow 0.2s;
42207
+ box-sizing: border-box;
42208
+ }
42209
+
42210
+ .myio-contract-devices-modal .field-group input:focus {
42211
+ outline: none;
42212
+ border-color: #3e1a7d;
42213
+ box-shadow: 0 0 0 3px rgba(62, 26, 125, 0.15);
42214
+ }
42215
+
42216
+ .myio-contract-devices-modal .field-key {
42217
+ font-size: 10px;
42218
+ color: #999;
42219
+ font-family: 'Courier New', monospace;
42220
+ }
42221
+
42222
+ .myio-contract-devices-modal .modal-footer {
42223
+ padding: 16px 24px;
42224
+ border-top: 1px solid #e0e0e0;
42225
+ display: flex;
42226
+ justify-content: flex-end;
42227
+ gap: 12px;
42228
+ background: white;
42229
+ }
42230
+
42231
+ .myio-contract-devices-modal .modal-footer button {
42232
+ padding: 10px 24px;
42233
+ border: none;
42234
+ border-radius: 6px;
42235
+ font-size: 14px;
42236
+ font-weight: 500;
42237
+ cursor: pointer;
42238
+ transition: all 0.2s;
42239
+ }
42240
+
42241
+ .myio-contract-devices-modal .btn-cancel {
42242
+ background: #6c757d;
42243
+ color: white;
42244
+ }
42245
+
42246
+ .myio-contract-devices-modal .btn-cancel:hover:not(:disabled) {
42247
+ background: #545b62;
42248
+ }
42249
+
42250
+ .myio-contract-devices-modal .btn-primary {
42251
+ background: #3e1a7d;
42252
+ color: white;
42253
+ }
42254
+
42255
+ .myio-contract-devices-modal .btn-primary:hover:not(:disabled) {
42256
+ background: #2d1458;
42257
+ }
42258
+
42259
+ .myio-contract-devices-modal .modal-footer button:disabled {
42260
+ opacity: 0.6;
42261
+ cursor: not-allowed;
42262
+ }
42263
+
42264
+ /* Responsive */
42265
+ @media (max-width: 900px) {
42266
+ .myio-contract-devices-modal .form-layout {
42267
+ grid-template-columns: 1fr;
42268
+ }
42269
+
42270
+ .myio-contract-devices-modal {
42271
+ width: 95vw !important;
42272
+ }
42273
+ }
42274
+
42275
+ /* Scrollbar */
42276
+ .myio-contract-devices-modal .modal-body::-webkit-scrollbar {
42277
+ width: 6px;
42278
+ }
42279
+
42280
+ .myio-contract-devices-modal .modal-body::-webkit-scrollbar-track {
42281
+ background: #f1f1f1;
42282
+ border-radius: 3px;
42283
+ }
42284
+
42285
+ .myio-contract-devices-modal .modal-body::-webkit-scrollbar-thumb {
42286
+ background: #c1c1c1;
42287
+ border-radius: 3px;
42288
+ }
42289
+ </style>
42290
+ `;
42291
+ }
42292
+ populateForm(data) {
42293
+ const setValue = (name, value) => {
42294
+ const input = this.form.querySelector(`[name="${name}"]`);
42295
+ if (input && value !== null && value !== void 0) {
42296
+ input.value = String(value);
42297
+ }
42298
+ };
42299
+ if (data.energy) {
42300
+ setValue("energy_total", data.energy.total);
42301
+ setValue("energy_entries", data.energy.entries);
42302
+ setValue("energy_commonArea", data.energy.commonArea);
42303
+ setValue("energy_stores", data.energy.stores);
42304
+ }
42305
+ if (data.water) {
42306
+ setValue("water_total", data.water.total);
42307
+ setValue("water_entries", data.water.entries);
42308
+ setValue("water_commonArea", data.water.commonArea);
42309
+ setValue("water_stores", data.water.stores);
42310
+ }
42311
+ if (data.temperature) {
42312
+ setValue("temperature_total", data.temperature.total);
42313
+ setValue("temperature_internal", data.temperature.internal);
42314
+ setValue("temperature_stores", data.temperature.stores);
42315
+ }
42316
+ }
42317
+ attachEventListeners() {
42318
+ const closeBtn = this.modal.querySelector(".close-btn");
42319
+ if (closeBtn) {
42320
+ closeBtn.addEventListener("click", (e) => {
42321
+ e.preventDefault();
42322
+ this.config.onClose();
42323
+ });
42324
+ }
42325
+ const cancelBtn = this.modal.querySelector(".btn-cancel");
42326
+ if (cancelBtn) {
42327
+ cancelBtn.addEventListener("click", (e) => {
42328
+ e.preventDefault();
42329
+ this.config.onClose();
42330
+ });
42331
+ }
42332
+ const saveBtn = this.modal.querySelector(".btn-save");
42333
+ if (saveBtn) {
42334
+ saveBtn.addEventListener("click", async (e) => {
42335
+ e.preventDefault();
42336
+ this.hideError();
42337
+ const formData = this.getFormData();
42338
+ await this.config.onSave(formData);
42339
+ });
42340
+ }
42341
+ this.container.addEventListener("click", (e) => {
42342
+ const target = e.target;
42343
+ if (target.classList.contains("myio-contract-devices-modal-overlay") && this.config.closeOnBackdrop !== false) {
42344
+ this.config.onClose();
42345
+ }
42346
+ });
42347
+ }
42348
+ setupAccessibility() {
42349
+ const firstInput = this.modal.querySelector("input");
42350
+ if (firstInput) {
42351
+ setTimeout(() => firstInput.focus(), 100);
42352
+ }
42353
+ this.modal.setAttribute("aria-labelledby", "modal-title");
42354
+ }
42355
+ setupFocusTrap() {
42356
+ this.focusTrapElements = Array.from(
42357
+ this.modal.querySelectorAll('button, input, [tabindex]:not([tabindex="-1"])')
42358
+ );
42359
+ this.modal.addEventListener("keydown", this.handleKeyDown.bind(this));
42360
+ }
42361
+ teardownFocusTrap() {
42362
+ this.modal.removeEventListener("keydown", this.handleKeyDown.bind(this));
42363
+ }
42364
+ handleKeyDown(event) {
42365
+ if (event.key === "Escape" && this.config.closeOnBackdrop !== false) {
42366
+ event.preventDefault();
42367
+ this.config.onClose();
42368
+ return;
42369
+ }
42370
+ if (event.key === "Tab") {
42371
+ const firstElement = this.focusTrapElements[0];
42372
+ const lastElement = this.focusTrapElements[this.focusTrapElements.length - 1];
42373
+ if (event.shiftKey) {
42374
+ if (document.activeElement === firstElement) {
42375
+ event.preventDefault();
42376
+ lastElement.focus();
42377
+ }
42378
+ } else {
42379
+ if (document.activeElement === lastElement) {
42380
+ event.preventDefault();
42381
+ firstElement.focus();
42382
+ }
42383
+ }
42384
+ }
42385
+ }
42386
+ };
42387
+
42388
+ // src/components/premium-modals/contract-devices/ContractDevicesPersister.ts
42389
+ var DefaultContractDevicesPersister = class {
42390
+ jwtToken;
42391
+ tbBaseUrl;
42392
+ constructor(jwtToken, apiConfig) {
42393
+ this.jwtToken = jwtToken;
42394
+ this.tbBaseUrl = apiConfig?.tbBaseUrl || window.location.origin;
42395
+ }
42396
+ async saveDeviceCounts(customerId, counts) {
42397
+ try {
42398
+ const payload = {};
42399
+ if (counts.energy.total !== null) {
42400
+ payload[DEVICE_COUNT_KEYS.energy.total] = counts.energy.total;
42401
+ }
42402
+ if (counts.energy.entries !== null) {
42403
+ payload[DEVICE_COUNT_KEYS.energy.entries] = counts.energy.entries;
42404
+ }
42405
+ if (counts.energy.commonArea !== null) {
42406
+ payload[DEVICE_COUNT_KEYS.energy.commonArea] = counts.energy.commonArea;
42407
+ }
42408
+ if (counts.energy.stores !== null) {
42409
+ payload[DEVICE_COUNT_KEYS.energy.stores] = counts.energy.stores;
42410
+ }
42411
+ if (counts.water.total !== null) {
42412
+ payload[DEVICE_COUNT_KEYS.water.total] = counts.water.total;
42413
+ }
42414
+ if (counts.water.entries !== null) {
42415
+ payload[DEVICE_COUNT_KEYS.water.entries] = counts.water.entries;
42416
+ }
42417
+ if (counts.water.commonArea !== null) {
42418
+ payload[DEVICE_COUNT_KEYS.water.commonArea] = counts.water.commonArea;
42419
+ }
42420
+ if (counts.water.stores !== null) {
42421
+ payload[DEVICE_COUNT_KEYS.water.stores] = counts.water.stores;
42422
+ }
42423
+ if (counts.temperature.total !== null) {
42424
+ payload[DEVICE_COUNT_KEYS.temperature.total] = counts.temperature.total;
42425
+ }
42426
+ if (counts.temperature.internal !== null) {
42427
+ payload[DEVICE_COUNT_KEYS.temperature.internal] = counts.temperature.internal;
42428
+ }
42429
+ if (counts.temperature.stores !== null) {
42430
+ payload[DEVICE_COUNT_KEYS.temperature.stores] = counts.temperature.stores;
42431
+ }
42432
+ console.log("[ContractDevicesPersister] Saving to CUSTOMER SERVER_SCOPE:", payload);
42433
+ const res = await fetch(
42434
+ `${this.tbBaseUrl}/api/plugins/telemetry/CUSTOMER/${customerId}/attributes/SERVER_SCOPE`,
42435
+ {
42436
+ method: "POST",
42437
+ headers: {
42438
+ "X-Authorization": `Bearer ${this.jwtToken}`,
42439
+ "Content-Type": "application/json"
42440
+ },
42441
+ body: JSON.stringify(payload)
42442
+ }
42443
+ );
42444
+ if (!res.ok) {
42445
+ throw this.createHttpError(res.status, await res.text().catch(() => ""));
42446
+ }
42447
+ return {
42448
+ ok: true,
42449
+ updatedKeys: Object.keys(payload),
42450
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
42451
+ };
42452
+ } catch (error) {
42453
+ console.error("[ContractDevicesPersister] Save failed:", error);
42454
+ return {
42455
+ ok: false,
42456
+ error: this.mapError(error)
42457
+ };
42458
+ }
42459
+ }
42460
+ createHttpError(status, body) {
42461
+ const error = new Error(`HTTP ${status}: ${body}`);
42462
+ error.status = status;
42463
+ error.body = body;
42464
+ return error;
42465
+ }
42466
+ mapError(error) {
42467
+ const status = error.status;
42468
+ if (status === 400) {
42469
+ return {
42470
+ code: "VALIDATION_ERROR",
42471
+ message: "Dados invalidos",
42472
+ userAction: "FIX_INPUT",
42473
+ cause: error
42474
+ };
42475
+ }
42476
+ if (status === 401) {
42477
+ return {
42478
+ code: "TOKEN_EXPIRED",
42479
+ message: "Token de autenticacao expirado",
42480
+ userAction: "RE_AUTH",
42481
+ cause: error
42482
+ };
42483
+ }
42484
+ if (status === 403) {
42485
+ return {
42486
+ code: "AUTH_ERROR",
42487
+ message: "Permissao insuficiente",
42488
+ userAction: "RE_AUTH",
42489
+ cause: error
42490
+ };
42491
+ }
42492
+ if (status === 404) {
42493
+ return {
42494
+ code: "NETWORK_ERROR",
42495
+ message: "Cliente nao encontrado",
42496
+ userAction: "CONTACT_ADMIN",
42497
+ cause: error
42498
+ };
42499
+ }
42500
+ if (status >= 500) {
42501
+ return {
42502
+ code: "NETWORK_ERROR",
42503
+ message: "Erro no servidor",
42504
+ userAction: "RETRY",
42505
+ cause: error
42506
+ };
42507
+ }
42508
+ return {
42509
+ code: "UNKNOWN_ERROR",
42510
+ message: error.message || "Erro desconhecido",
42511
+ userAction: "CONTACT_ADMIN",
42512
+ cause: error
42513
+ };
42514
+ }
42515
+ };
42516
+
42517
+ // src/components/premium-modals/contract-devices/ContractDevicesFetcher.ts
42518
+ var DefaultContractDevicesFetcher = class {
42519
+ jwtToken;
42520
+ tbBaseUrl;
42521
+ constructor(jwtToken, apiConfig) {
42522
+ this.jwtToken = jwtToken;
42523
+ this.tbBaseUrl = apiConfig?.tbBaseUrl || window.location.origin;
42524
+ }
42525
+ async fetchCurrentCounts(customerId) {
42526
+ try {
42527
+ const keys = [
42528
+ DEVICE_COUNT_KEYS.energy.total,
42529
+ DEVICE_COUNT_KEYS.energy.entries,
42530
+ DEVICE_COUNT_KEYS.energy.commonArea,
42531
+ DEVICE_COUNT_KEYS.energy.stores,
42532
+ DEVICE_COUNT_KEYS.water.total,
42533
+ DEVICE_COUNT_KEYS.water.entries,
42534
+ DEVICE_COUNT_KEYS.water.commonArea,
42535
+ DEVICE_COUNT_KEYS.water.stores,
42536
+ DEVICE_COUNT_KEYS.temperature.total,
42537
+ DEVICE_COUNT_KEYS.temperature.internal,
42538
+ DEVICE_COUNT_KEYS.temperature.stores
42539
+ ];
42540
+ const url = `${this.tbBaseUrl}/api/plugins/telemetry/CUSTOMER/${customerId}/values/attributes/SERVER_SCOPE?keys=${keys.join(",")}`;
42541
+ console.log("[ContractDevicesFetcher] Fetching from:", url);
42542
+ const res = await fetch(url, {
42543
+ headers: {
42544
+ "X-Authorization": `Bearer ${this.jwtToken}`,
42545
+ "Content-Type": "application/json"
42546
+ }
42547
+ });
42548
+ if (!res.ok) {
42549
+ console.warn("[ContractDevicesFetcher] Fetch failed:", res.status);
42550
+ return {};
42551
+ }
42552
+ const data = await res.json();
42553
+ console.log("[ContractDevicesFetcher] Received data:", data);
42554
+ return this.parseAttributesToCounts(data);
42555
+ } catch (error) {
42556
+ console.error("[ContractDevicesFetcher] Error fetching counts:", error);
42557
+ return {};
42558
+ }
42559
+ }
42560
+ parseAttributesToCounts(attributes) {
42561
+ const getValue = (key) => {
42562
+ const attr = attributes.find((a) => a.key === key);
42563
+ if (!attr) return null;
42564
+ const num = parseInt(attr.value, 10);
42565
+ return isNaN(num) ? null : num;
42566
+ };
42567
+ return {
42568
+ energy: {
42569
+ total: getValue(DEVICE_COUNT_KEYS.energy.total),
42570
+ entries: getValue(DEVICE_COUNT_KEYS.energy.entries),
42571
+ commonArea: getValue(DEVICE_COUNT_KEYS.energy.commonArea),
42572
+ stores: getValue(DEVICE_COUNT_KEYS.energy.stores)
42573
+ },
42574
+ water: {
42575
+ total: getValue(DEVICE_COUNT_KEYS.water.total),
42576
+ entries: getValue(DEVICE_COUNT_KEYS.water.entries),
42577
+ commonArea: getValue(DEVICE_COUNT_KEYS.water.commonArea),
42578
+ stores: getValue(DEVICE_COUNT_KEYS.water.stores)
42579
+ },
42580
+ temperature: {
42581
+ total: getValue(DEVICE_COUNT_KEYS.temperature.total),
42582
+ internal: getValue(DEVICE_COUNT_KEYS.temperature.internal),
42583
+ stores: getValue(DEVICE_COUNT_KEYS.temperature.stores)
42584
+ }
42585
+ };
42586
+ }
42587
+ };
42588
+
42589
+ // src/components/premium-modals/contract-devices/ContractDevicesController.ts
42590
+ var ContractDevicesController = class {
42591
+ params;
42592
+ view = null;
42593
+ persister;
42594
+ fetcher;
42595
+ constructor(params) {
42596
+ this.params = params;
42597
+ this.persister = new DefaultContractDevicesPersister(
42598
+ params.jwtToken,
42599
+ params.api
42600
+ );
42601
+ this.fetcher = new DefaultContractDevicesFetcher(
42602
+ params.jwtToken,
42603
+ params.api
42604
+ );
42605
+ }
42606
+ async show() {
42607
+ let seedData = this.params.seed || {};
42608
+ try {
42609
+ const existingCounts = await this.fetcher.fetchCurrentCounts(this.params.customerId);
42610
+ seedData = this.mergeCounts(seedData, existingCounts);
42611
+ console.log("[ContractDevicesController] Merged seed data:", seedData);
42612
+ } catch (error) {
42613
+ console.warn("[ContractDevicesController] Failed to fetch existing counts:", error);
42614
+ }
42615
+ const viewConfig = {
42616
+ title: this.params.ui?.title || "Configurar Dispositivos Contratados",
42617
+ width: this.params.ui?.width || 800,
42618
+ closeOnBackdrop: this.params.ui?.closeOnBackdrop !== false,
42619
+ customerName: this.params.customerName,
42620
+ onSave: this.handleSave.bind(this),
42621
+ onClose: this.handleClose.bind(this)
42622
+ };
42623
+ this.view = new ContractDevicesModalView(viewConfig);
42624
+ this.view.render(seedData);
42625
+ }
42626
+ async handleSave(formData) {
42627
+ if (!this.view) return;
42628
+ const validationError = this.validateTotals(formData);
42629
+ if (validationError) {
42630
+ this.view.showError(validationError);
42631
+ return;
42632
+ }
42633
+ this.view.showLoadingState(true);
42634
+ this.view.hideError();
42635
+ try {
42636
+ const result = await this.persister.saveDeviceCounts(
42637
+ this.params.customerId,
42638
+ formData
42639
+ );
42640
+ if (result.ok) {
42641
+ console.log("[ContractDevicesController] Save successful:", result);
42642
+ if (this.params.onSaved) {
42643
+ this.params.onSaved(result);
42644
+ }
42645
+ this.handleClose();
42646
+ } else {
42647
+ console.error("[ContractDevicesController] Save failed:", result.error);
42648
+ this.view.showError(result.error?.message || "Erro ao salvar configuracoes");
42649
+ if (this.params.onError && result.error) {
42650
+ this.params.onError(result.error);
42651
+ }
42652
+ }
42653
+ } catch (error) {
42654
+ console.error("[ContractDevicesController] Unexpected error:", error);
42655
+ this.view.showError(error.message || "Erro inesperado");
42656
+ if (this.params.onError) {
42657
+ this.params.onError({
42658
+ code: "UNKNOWN_ERROR",
42659
+ message: error.message || "Erro desconhecido",
42660
+ cause: error
42661
+ });
42662
+ }
42663
+ } finally {
42664
+ if (this.view) {
42665
+ this.view.showLoadingState(false);
42666
+ }
42667
+ }
42668
+ }
42669
+ handleClose() {
42670
+ if (this.view) {
42671
+ this.view.close();
42672
+ this.view = null;
42673
+ }
42674
+ if (this.params.onClose) {
42675
+ this.params.onClose();
42676
+ }
42677
+ }
42678
+ /**
42679
+ * Validate that totals match sum of components for each domain
42680
+ * Returns error message if validation fails, null if valid
42681
+ */
42682
+ validateTotals(formData) {
42683
+ const errors = [];
42684
+ if (formData.energy.total !== null) {
42685
+ const energySum = (formData.energy.entries || 0) + (formData.energy.commonArea || 0) + (formData.energy.stores || 0);
42686
+ if (formData.energy.total !== energySum) {
42687
+ errors.push(`Energia: Total (${formData.energy.total}) deve ser igual a Entradas + Area Comum + Lojas (${energySum})`);
42688
+ }
42689
+ }
42690
+ if (formData.water.total !== null) {
42691
+ const waterSum = (formData.water.entries || 0) + (formData.water.commonArea || 0) + (formData.water.stores || 0);
42692
+ if (formData.water.total !== waterSum) {
42693
+ errors.push(`Agua: Total (${formData.water.total}) deve ser igual a Entradas + Area Comum + Lojas (${waterSum})`);
42694
+ }
42695
+ }
42696
+ if (formData.temperature.total !== null) {
42697
+ const tempSum = (formData.temperature.internal || 0) + (formData.temperature.stores || 0);
42698
+ if (formData.temperature.total !== tempSum) {
42699
+ errors.push(`Temperatura: Total (${formData.temperature.total}) deve ser igual a Sensores Internos + Lojas (${tempSum})`);
42700
+ }
42701
+ }
42702
+ return errors.length > 0 ? errors.join("\n") : null;
42703
+ }
42704
+ mergeCounts(seed, fetched) {
42705
+ return {
42706
+ energy: {
42707
+ total: fetched.energy?.total ?? seed.energy?.total ?? null,
42708
+ entries: fetched.energy?.entries ?? seed.energy?.entries ?? null,
42709
+ commonArea: fetched.energy?.commonArea ?? seed.energy?.commonArea ?? null,
42710
+ stores: fetched.energy?.stores ?? seed.energy?.stores ?? null
42711
+ },
42712
+ water: {
42713
+ total: fetched.water?.total ?? seed.water?.total ?? null,
42714
+ entries: fetched.water?.entries ?? seed.water?.entries ?? null,
42715
+ commonArea: fetched.water?.commonArea ?? seed.water?.commonArea ?? null,
42716
+ stores: fetched.water?.stores ?? seed.water?.stores ?? null
42717
+ },
42718
+ temperature: {
42719
+ total: fetched.temperature?.total ?? seed.temperature?.total ?? null,
42720
+ internal: fetched.temperature?.internal ?? seed.temperature?.internal ?? null,
42721
+ stores: fetched.temperature?.stores ?? seed.temperature?.stores ?? null
42722
+ }
42723
+ };
42724
+ }
42725
+ };
42726
+
42727
+ // src/components/premium-modals/contract-devices/openContractDevicesModal.ts
42728
+ async function openContractDevicesModal(params) {
42729
+ if (!params.jwtToken) {
42730
+ throw new Error("jwtToken is required for contract devices persistence");
42731
+ }
42732
+ if (!params.customerId) {
42733
+ throw new Error("customerId is required");
42734
+ }
42735
+ console.info("[openContractDevicesModal] Initializing contract devices modal", {
42736
+ customerId: params.customerId,
42737
+ customerName: params.customerName,
42738
+ hasJwtToken: !!params.jwtToken,
42739
+ hasSeedData: !!params.seed
42740
+ });
42741
+ const controller = new ContractDevicesController(params);
42742
+ try {
42743
+ await controller.show();
42744
+ } catch (error) {
42745
+ console.error("[openContractDevicesModal] Error:", error);
42746
+ if (params.onError) {
42747
+ params.onError({
42748
+ code: "UNKNOWN_ERROR",
42749
+ message: error.message || "Erro ao abrir modal de dispositivos contratados",
42750
+ cause: error
42751
+ });
42752
+ }
42753
+ throw error;
42754
+ }
42755
+ }
42756
+
41798
42757
  exports.ANNOTATION_TYPE_COLORS = ANNOTATION_TYPE_COLORS;
41799
42758
  exports.ANNOTATION_TYPE_LABELS = ANNOTATION_TYPE_LABELS;
41800
42759
  exports.ANNOTATION_TYPE_LABELS_EN = ANNOTATION_TYPE_LABELS_EN;
@@ -41810,6 +42769,7 @@
41810
42769
  exports.DEFAULT_GAS_GROUP_COLORS = DEFAULT_GAS_GROUP_COLORS;
41811
42770
  exports.DEFAULT_SHOPPING_COLORS = DEFAULT_SHOPPING_COLORS;
41812
42771
  exports.DEFAULT_WATER_GROUP_COLORS = DEFAULT_WATER_GROUP_COLORS;
42772
+ exports.DEVICE_COUNT_KEYS = DEVICE_COUNT_KEYS;
41813
42773
  exports.DeviceComparisonTooltip = DeviceComparisonTooltip;
41814
42774
  exports.DeviceStatusType = DeviceStatusType;
41815
42775
  exports.EXPORT_DEFAULT_COLORS = EXPORT_DEFAULT_COLORS;
@@ -41931,6 +42891,7 @@
41931
42891
  exports.myioExportData = myioExportData;
41932
42892
  exports.normalizeRecipients = normalizeRecipients;
41933
42893
  exports.numbers = numbers_exports;
42894
+ exports.openContractDevicesModal = openContractDevicesModal;
41934
42895
  exports.openDashboardPopup = openDashboardPopup;
41935
42896
  exports.openDashboardPopupAllReport = openDashboardPopupAllReport;
41936
42897
  exports.openDashboardPopupEnergy = openDashboardPopupEnergy;