myio-js-library 0.1.164 → 0.1.166

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -574,6 +574,10 @@ __export(index_exports, {
574
574
  CONSUMPTION_THEME_COLORS: () => THEME_COLORS,
575
575
  ConnectionStatusType: () => ConnectionStatusType,
576
576
  DEFAULT_CLAMP_RANGE: () => DEFAULT_CLAMP_RANGE,
577
+ DEFAULT_ENERGY_GROUP_COLORS: () => DEFAULT_ENERGY_GROUP_COLORS,
578
+ DEFAULT_GAS_GROUP_COLORS: () => DEFAULT_GAS_GROUP_COLORS,
579
+ DEFAULT_SHOPPING_COLORS: () => DEFAULT_SHOPPING_COLORS,
580
+ DEFAULT_WATER_GROUP_COLORS: () => DEFAULT_WATER_GROUP_COLORS,
577
581
  DeviceStatusType: () => DeviceStatusType,
578
582
  EXPORT_DEFAULT_COLORS: () => EXPORT_DEFAULT_COLORS,
579
583
  EXPORT_DOMAIN_ICONS: () => EXPORT_DOMAIN_ICONS,
@@ -587,6 +591,7 @@ __export(index_exports, {
587
591
  addDetectionContext: () => addDetectionContext,
588
592
  addNamespace: () => addNamespace,
589
593
  aggregateByDay: () => aggregateByDay,
594
+ assignShoppingColors: () => assignShoppingColors,
590
595
  averageByDay: () => averageByDay,
591
596
  buildListItemsThingsboardByUniqueDatasource: () => buildListItemsThingsboardByUniqueDatasource,
592
597
  buildMyioIngestionAuth: () => buildMyioIngestionAuth,
@@ -608,6 +613,7 @@ __export(index_exports, {
608
613
  createConsumptionChartWidget: () => createConsumptionChartWidget,
609
614
  createConsumptionModal: () => createConsumptionModal,
610
615
  createDateRangePicker: () => createDateRangePicker2,
616
+ createDistributionChartWidget: () => createDistributionChartWidget,
611
617
  createInputDateRangePickerInsideDIV: () => createInputDateRangePickerInsideDIV,
612
618
  createModalHeader: () => createModalHeader,
613
619
  decodePayload: () => decodePayload,
@@ -646,11 +652,16 @@ __export(index_exports, {
646
652
  getAvailableContexts: () => getAvailableContexts,
647
653
  getConnectionStatusIcon: () => getConnectionStatusIcon,
648
654
  getDateRangeArray: () => getDateRangeArray,
655
+ getDefaultGroupColors: () => getDefaultGroupColors,
649
656
  getDeviceStatusIcon: () => getDeviceStatusIcon,
650
657
  getDeviceStatusInfo: () => getDeviceStatusInfo,
658
+ getDistributionThemeColors: () => getThemeColors2,
659
+ getGroupColor: () => getGroupColor,
660
+ getHashColor: () => getHashColor,
651
661
  getModalHeaderStyles: () => getModalHeaderStyles,
652
662
  getSaoPauloISOString: () => getSaoPauloISOString,
653
663
  getSaoPauloISOStringFixed: () => getSaoPauloISOStringFixed,
664
+ getShoppingColor: () => getShoppingColor,
654
665
  getValueByDatakey: () => getValueByDatakey,
655
666
  getValueByDatakeyLegacy: () => getValueByDatakeyLegacy,
656
667
  getWaterCategories: () => getWaterCategories,
@@ -20657,7 +20668,7 @@ function renderModal(container, state, modalId, error) {
20657
20668
  const contentMaxHeight = isMaximized ? "100vh" : "95vh";
20658
20669
  const contentBorderRadius = isMaximized ? "0" : "10px";
20659
20670
  container.innerHTML = `
20660
- <div class="myio-temp-modal-overlay" style="
20671
+ <div class="myio-temp-modal-overlay myio-modal-scope" style="
20661
20672
  position: fixed; top: 0; left: 0; width: 100%; height: 100%;
20662
20673
  background: rgba(0, 0, 0, 0.5); z-index: 9998;
20663
20674
  display: flex; justify-content: center; align-items: center;
@@ -20912,6 +20923,22 @@ function renderModal(container, state, modalId, error) {
20912
20923
  background: rgba(255, 255, 255, 0.1) !important;
20913
20924
  color: white !important;
20914
20925
  }
20926
+
20927
+ /* DateRangePicker styles */
20928
+ ${CSS_TOKENS}
20929
+ ${DATERANGEPICKER_STYLES}
20930
+
20931
+ /* Fix DateRangePicker buttons alignment */
20932
+ .myio-modal-scope .daterangepicker .drp-buttons {
20933
+ display: flex;
20934
+ justify-content: flex-end;
20935
+ align-items: center;
20936
+ gap: 8px;
20937
+ }
20938
+ .myio-modal-scope .daterangepicker .drp-buttons .btn {
20939
+ display: inline-block;
20940
+ margin-left: 0;
20941
+ }
20915
20942
  </style>
20916
20943
  `;
20917
20944
  }
@@ -23707,11 +23734,16 @@ function createConsumptionModal(config) {
23707
23734
  let isMaximized = false;
23708
23735
  const domainCfg = DOMAIN_CONFIG3[config.domain] || { name: config.domain, icon: "\u{1F4CA}" };
23709
23736
  const title = config.title || `${domainCfg.name} - Hist\xF3rico de Consumo`;
23710
- function getThemeColors2() {
23737
+ function getThemeColors3() {
23711
23738
  return THEME_COLORS[currentTheme];
23712
23739
  }
23740
+ const consolidadoIcon = `<svg viewBox="0 0 16 16" fill="currentColor" style="width:14px;height:14px;pointer-events:none"><rect x="3" y="3" width="10" height="10" rx="2"/></svg>`;
23741
+ const porShoppingIcon = `<svg viewBox="0 0 16 16" fill="currentColor" style="width:14px;height:14px;pointer-events:none"><rect x="1" y="1" width="6" height="6" rx="1"/><rect x="9" y="1" width="6" height="6" rx="1"/><rect x="1" y="9" width="6" height="6" rx="1"/><rect x="9" y="9" width="6" height="6" rx="1"/></svg>`;
23742
+ const lineChartIcon = `<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:14px;height:14px;pointer-events:none"><polyline points="2,12 5,7 9,9 14,3"/></svg>`;
23743
+ const barChartIcon = `<svg viewBox="0 0 16 16" fill="currentColor" style="width:14px;height:14px;pointer-events:none"><rect x="1" y="9" width="3" height="6" rx="0.5"/><rect x="6" y="5" width="3" height="10" rx="0.5"/><rect x="11" y="7" width="3" height="8" rx="0.5"/></svg>`;
23744
+ const showSettingsButton = config.showSettingsButton ?? true;
23713
23745
  function renderModal4() {
23714
- const colors = getThemeColors2();
23746
+ const colors = getThemeColors3();
23715
23747
  const exportFormats = config.exportFormats || ["csv"];
23716
23748
  headerInstance = createModalHeader({
23717
23749
  id: modalId,
@@ -23744,7 +23776,55 @@ function createConsumptionModal(config) {
23744
23776
  instance.close();
23745
23777
  }
23746
23778
  });
23779
+ const btnBaseStyle = `
23780
+ display: flex;
23781
+ align-items: center;
23782
+ justify-content: center;
23783
+ gap: 6px;
23784
+ padding: 6px 12px;
23785
+ border: none;
23786
+ border-radius: 6px;
23787
+ font-size: 12px;
23788
+ font-weight: 500;
23789
+ cursor: pointer;
23790
+ transition: all 0.2s;
23791
+ white-space: nowrap;
23792
+ `.replace(/\s+/g, " ").trim();
23793
+ const tabBgColor = currentTheme === "dark" ? "#4b5563" : "#e5e7eb";
23794
+ const activeColor = "#3e1a7d";
23795
+ const inactiveTextColor = colors.text;
23747
23796
  return `
23797
+ <style>
23798
+ .myio-modal-tab-btn {
23799
+ ${btnBaseStyle}
23800
+ }
23801
+ .myio-modal-tab-btn:hover {
23802
+ opacity: 0.85;
23803
+ }
23804
+ .myio-modal-tab-btn.active {
23805
+ background: ${activeColor} !important;
23806
+ color: white !important;
23807
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
23808
+ }
23809
+ .myio-modal-tab-btn svg {
23810
+ pointer-events: none;
23811
+ }
23812
+ .myio-modal-settings-btn {
23813
+ background: transparent;
23814
+ border: 1px solid ${colors.border};
23815
+ font-size: 16px;
23816
+ cursor: pointer;
23817
+ padding: 6px 10px;
23818
+ border-radius: 6px;
23819
+ transition: all 0.2s;
23820
+ color: ${colors.text};
23821
+ }
23822
+ .myio-modal-settings-btn:hover {
23823
+ background: ${activeColor};
23824
+ border-color: ${activeColor};
23825
+ color: white;
23826
+ }
23827
+ </style>
23748
23828
  <div class="myio-consumption-modal-overlay" style="
23749
23829
  position: fixed;
23750
23830
  top: 0;
@@ -23775,59 +23855,44 @@ function createConsumptionModal(config) {
23775
23855
  <!-- Controls Bar -->
23776
23856
  <div class="myio-consumption-modal-controls" style="
23777
23857
  display: flex;
23778
- gap: 16px;
23858
+ gap: 12px;
23779
23859
  padding: 12px 16px;
23780
23860
  background: ${currentTheme === "dark" ? "#374151" : "#f7f7f7"};
23781
23861
  border-bottom: 1px solid ${colors.border};
23782
23862
  align-items: center;
23783
23863
  flex-wrap: wrap;
23784
23864
  ">
23865
+ <!-- Settings Button -->
23866
+ ${showSettingsButton ? `
23867
+ <button id="${modalId}-settings-btn" class="myio-modal-settings-btn" title="Configura\xE7\xF5es">\u2699\uFE0F</button>
23868
+ ` : ""}
23869
+
23785
23870
  <!-- Viz Mode Tabs -->
23786
- <div style="display: flex; gap: 2px; background: ${currentTheme === "dark" ? "#4b5563" : "#e5e7eb"}; border-radius: 8px; padding: 2px;">
23787
- <button id="${modalId}-viz-total" style="
23788
- padding: 6px 12px;
23789
- border: none;
23790
- border-radius: 6px;
23791
- font-size: 13px;
23792
- cursor: pointer;
23793
- transition: all 0.2s;
23794
- background: ${currentVizMode === "total" ? "#3e1a7d" : "transparent"};
23795
- color: ${currentVizMode === "total" ? "white" : colors.text};
23796
- ">Consolidado</button>
23797
- <button id="${modalId}-viz-separate" style="
23798
- padding: 6px 12px;
23799
- border: none;
23800
- border-radius: 6px;
23801
- font-size: 13px;
23802
- cursor: pointer;
23803
- transition: all 0.2s;
23804
- background: ${currentVizMode === "separate" ? "#3e1a7d" : "transparent"};
23805
- color: ${currentVizMode === "separate" ? "white" : colors.text};
23806
- ">Por Shopping</button>
23871
+ <div style="display: flex; gap: 2px; background: ${tabBgColor}; border-radius: 8px; padding: 3px;">
23872
+ <button id="${modalId}-viz-total" class="myio-modal-tab-btn ${currentVizMode === "total" ? "active" : ""}"
23873
+ data-viz="total" title="Consolidado"
23874
+ style="background: ${currentVizMode === "total" ? activeColor : "transparent"}; color: ${currentVizMode === "total" ? "white" : inactiveTextColor};">
23875
+ ${consolidadoIcon}
23876
+ </button>
23877
+ <button id="${modalId}-viz-separate" class="myio-modal-tab-btn ${currentVizMode === "separate" ? "active" : ""}"
23878
+ data-viz="separate" title="Por Shopping"
23879
+ style="background: ${currentVizMode === "separate" ? activeColor : "transparent"}; color: ${currentVizMode === "separate" ? "white" : inactiveTextColor};">
23880
+ ${porShoppingIcon}
23881
+ </button>
23807
23882
  </div>
23808
23883
 
23809
23884
  <!-- Chart Type Tabs -->
23810
- <div style="display: flex; gap: 2px; background: ${currentTheme === "dark" ? "#4b5563" : "#e5e7eb"}; border-radius: 8px; padding: 2px;">
23811
- <button id="${modalId}-type-line" style="
23812
- padding: 6px 12px;
23813
- border: none;
23814
- border-radius: 6px;
23815
- font-size: 13px;
23816
- cursor: pointer;
23817
- transition: all 0.2s;
23818
- background: ${currentChartType === "line" ? "#3e1a7d" : "transparent"};
23819
- color: ${currentChartType === "line" ? "white" : colors.text};
23820
- ">Linhas</button>
23821
- <button id="${modalId}-type-bar" style="
23822
- padding: 6px 12px;
23823
- border: none;
23824
- border-radius: 6px;
23825
- font-size: 13px;
23826
- cursor: pointer;
23827
- transition: all 0.2s;
23828
- background: ${currentChartType === "bar" ? "#3e1a7d" : "transparent"};
23829
- color: ${currentChartType === "bar" ? "white" : colors.text};
23830
- ">Barras</button>
23885
+ <div style="display: flex; gap: 2px; background: ${tabBgColor}; border-radius: 8px; padding: 3px;">
23886
+ <button id="${modalId}-type-line" class="myio-modal-tab-btn ${currentChartType === "line" ? "active" : ""}"
23887
+ data-type="line" title="Gr\xE1fico de Linhas"
23888
+ style="background: ${currentChartType === "line" ? activeColor : "transparent"}; color: ${currentChartType === "line" ? "white" : inactiveTextColor};">
23889
+ ${lineChartIcon}
23890
+ </button>
23891
+ <button id="${modalId}-type-bar" class="myio-modal-tab-btn ${currentChartType === "bar" ? "active" : ""}"
23892
+ data-type="bar" title="Gr\xE1fico de Barras"
23893
+ style="background: ${currentChartType === "bar" ? activeColor : "transparent"}; color: ${currentChartType === "bar" ? "white" : inactiveTextColor};">
23894
+ ${barChartIcon}
23895
+ </button>
23831
23896
  </div>
23832
23897
  </div>
23833
23898
 
@@ -23848,6 +23913,11 @@ function createConsumptionModal(config) {
23848
23913
  function setupListeners() {
23849
23914
  if (!modalElement) return;
23850
23915
  headerInstance?.attachListeners();
23916
+ if (showSettingsButton) {
23917
+ document.getElementById(`${modalId}-settings-btn`)?.addEventListener("click", () => {
23918
+ config.onSettingsClick?.();
23919
+ });
23920
+ }
23851
23921
  document.getElementById(`${modalId}-viz-total`)?.addEventListener("click", () => {
23852
23922
  currentVizMode = "total";
23853
23923
  chartInstance?.setVizMode("total");
@@ -23882,25 +23952,30 @@ function createConsumptionModal(config) {
23882
23952
  modalElement.__handleKeydown = handleKeydown;
23883
23953
  }
23884
23954
  function updateControlStyles() {
23885
- const colors = getThemeColors2();
23955
+ const colors = getThemeColors3();
23956
+ const activeColor = "#3e1a7d";
23886
23957
  const vizTotalBtn = document.getElementById(`${modalId}-viz-total`);
23887
23958
  const vizSeparateBtn = document.getElementById(`${modalId}-viz-separate`);
23888
23959
  if (vizTotalBtn) {
23889
- vizTotalBtn.style.background = currentVizMode === "total" ? "#3e1a7d" : "transparent";
23960
+ vizTotalBtn.classList.toggle("active", currentVizMode === "total");
23961
+ vizTotalBtn.style.background = currentVizMode === "total" ? activeColor : "transparent";
23890
23962
  vizTotalBtn.style.color = currentVizMode === "total" ? "white" : colors.text;
23891
23963
  }
23892
23964
  if (vizSeparateBtn) {
23893
- vizSeparateBtn.style.background = currentVizMode === "separate" ? "#3e1a7d" : "transparent";
23965
+ vizSeparateBtn.classList.toggle("active", currentVizMode === "separate");
23966
+ vizSeparateBtn.style.background = currentVizMode === "separate" ? activeColor : "transparent";
23894
23967
  vizSeparateBtn.style.color = currentVizMode === "separate" ? "white" : colors.text;
23895
23968
  }
23896
23969
  const typeLineBtn = document.getElementById(`${modalId}-type-line`);
23897
23970
  const typeBarBtn = document.getElementById(`${modalId}-type-bar`);
23898
23971
  if (typeLineBtn) {
23899
- typeLineBtn.style.background = currentChartType === "line" ? "#3e1a7d" : "transparent";
23972
+ typeLineBtn.classList.toggle("active", currentChartType === "line");
23973
+ typeLineBtn.style.background = currentChartType === "line" ? activeColor : "transparent";
23900
23974
  typeLineBtn.style.color = currentChartType === "line" ? "white" : colors.text;
23901
23975
  }
23902
23976
  if (typeBarBtn) {
23903
- typeBarBtn.style.background = currentChartType === "bar" ? "#3e1a7d" : "transparent";
23977
+ typeBarBtn.classList.toggle("active", currentChartType === "bar");
23978
+ typeBarBtn.style.background = currentChartType === "bar" ? activeColor : "transparent";
23904
23979
  typeBarBtn.style.color = currentChartType === "bar" ? "white" : colors.text;
23905
23980
  }
23906
23981
  }
@@ -24026,18 +24101,11 @@ function getWidgetStyles(theme, primaryColor) {
24026
24101
 
24027
24102
  .myio-chart-widget-title {
24028
24103
  margin: 0;
24029
- font-size: 16px;
24104
+ font-size: 14px;
24030
24105
  font-weight: 600;
24031
24106
  color: ${colors.text};
24032
24107
  }
24033
24108
 
24034
- .myio-chart-widget-controls {
24035
- display: flex;
24036
- align-items: center;
24037
- gap: 12px;
24038
- flex-wrap: wrap;
24039
- }
24040
-
24041
24109
  .myio-chart-widget-tabs {
24042
24110
  display: flex;
24043
24111
  gap: 2px;
@@ -24057,6 +24125,20 @@ function getWidgetStyles(theme, primaryColor) {
24057
24125
  border-radius: 6px;
24058
24126
  transition: all 0.2s;
24059
24127
  white-space: nowrap;
24128
+ display: flex;
24129
+ align-items: center;
24130
+ justify-content: center;
24131
+ gap: 4px;
24132
+ }
24133
+
24134
+ .myio-chart-widget-tab.icon-only {
24135
+ padding: 6px 10px;
24136
+ }
24137
+
24138
+ .myio-chart-widget-tab svg {
24139
+ width: 16px;
24140
+ height: 16px;
24141
+ pointer-events: none;
24060
24142
  }
24061
24143
 
24062
24144
  .myio-chart-widget-tab:hover {
@@ -24190,7 +24272,7 @@ function getWidgetStyles(theme, primaryColor) {
24190
24272
  background: ${colors.chartBackground};
24191
24273
  border-radius: 10px;
24192
24274
  width: 90%;
24193
- max-width: 600px;
24275
+ max-width: 860px;
24194
24276
  max-height: 90vh;
24195
24277
  display: flex;
24196
24278
  flex-direction: column;
@@ -24207,7 +24289,7 @@ function getWidgetStyles(theme, primaryColor) {
24207
24289
  overflow-y: auto;
24208
24290
  display: flex;
24209
24291
  flex-direction: column;
24210
- gap: 20px;
24292
+ gap: 12px;
24211
24293
  }
24212
24294
 
24213
24295
  .myio-settings-section {
@@ -24250,10 +24332,10 @@ function getWidgetStyles(theme, primaryColor) {
24250
24332
 
24251
24333
  .myio-settings-input,
24252
24334
  .myio-settings-select {
24253
- padding: 10px 14px;
24335
+ padding: 8px 12px;
24254
24336
  border: 1px solid ${colors.border};
24255
24337
  border-radius: 8px;
24256
- font-size: 14px;
24338
+ font-size: 12px;
24257
24339
  background: ${colors.chartBackground};
24258
24340
  color: ${colors.text};
24259
24341
  width: 100%;
@@ -24285,6 +24367,10 @@ function getWidgetStyles(theme, primaryColor) {
24285
24367
  border-radius: 6px;
24286
24368
  transition: all 0.2s;
24287
24369
  white-space: nowrap;
24370
+ display: flex;
24371
+ align-items: center;
24372
+ justify-content: center;
24373
+ gap: 6px;
24288
24374
  }
24289
24375
 
24290
24376
  .myio-settings-tab:hover {
@@ -24342,13 +24428,17 @@ function getWidgetStyles(theme, primaryColor) {
24342
24428
  }
24343
24429
 
24344
24430
  .myio-settings-context-group {
24345
- margin-bottom: 8px;
24431
+ margin-bottom: 12px;
24346
24432
  }
24347
24433
 
24348
24434
  .myio-settings-context-group:last-child {
24349
24435
  margin-bottom: 0;
24350
24436
  }
24351
24437
 
24438
+ .myio-settings-section + .myio-settings-section {
24439
+ margin-top: 12px;
24440
+ }
24441
+
24352
24442
  /* Dropdown styles */
24353
24443
  .myio-settings-dropdown-container {
24354
24444
  position: relative;
@@ -24452,6 +24542,23 @@ function getWidgetStyles(theme, primaryColor) {
24452
24542
  opacity: 1 !important;
24453
24543
  transform: scale(1.2);
24454
24544
  }
24545
+
24546
+ /* DateRangePicker styles (CSS tokens + premium styling) */
24547
+ ${CSS_TOKENS}
24548
+ ${DATERANGEPICKER_STYLES}
24549
+
24550
+ /* Fix DateRangePicker buttons alignment */
24551
+ .myio-modal-scope .daterangepicker .drp-buttons {
24552
+ display: flex;
24553
+ justify-content: flex-end;
24554
+ align-items: center;
24555
+ gap: 8px;
24556
+ }
24557
+
24558
+ .myio-modal-scope .daterangepicker .drp-buttons .btn {
24559
+ display: inline-block;
24560
+ margin-left: 0;
24561
+ }
24455
24562
  `;
24456
24563
  }
24457
24564
  function createConsumptionChartWidget(config) {
@@ -24461,6 +24568,7 @@ function createConsumptionChartWidget(config) {
24461
24568
  let styleElement = null;
24462
24569
  let settingsModalElement = null;
24463
24570
  let settingsHeaderInstance = null;
24571
+ let dateRangePickerInstance = null;
24464
24572
  let currentTheme = config.theme ?? "light";
24465
24573
  let currentChartType = config.defaultChartType ?? "line";
24466
24574
  let currentVizMode = config.defaultVizMode ?? "total";
@@ -24472,6 +24580,8 @@ function createConsumptionChartWidget(config) {
24472
24580
  let tempVizMode = currentVizMode;
24473
24581
  let tempTheme = currentTheme;
24474
24582
  let tempIdealRange = currentIdealRange;
24583
+ let tempStartDate = null;
24584
+ let tempEndDate = null;
24475
24585
  let currentSuggestion = null;
24476
24586
  const domainCfg = DOMAIN_CONFIG4[config.domain] || DOMAIN_CONFIG4.energy;
24477
24587
  const primaryColor = config.colors?.primary || domainCfg.color;
@@ -24487,6 +24597,10 @@ function createConsumptionChartWidget(config) {
24487
24597
  return `${domainName} dos \xFAltimos ${currentPeriod} dias`;
24488
24598
  }
24489
24599
  function renderHTML() {
24600
+ const consolidadoIcon = `<svg viewBox="0 0 16 16" fill="currentColor"><rect x="3" y="3" width="10" height="10" rx="2"/></svg>`;
24601
+ const porShoppingIcon = `<svg viewBox="0 0 16 16" fill="currentColor"><rect x="1" y="1" width="6" height="6" rx="1"/><rect x="9" y="1" width="6" height="6" rx="1"/><rect x="1" y="9" width="6" height="6" rx="1"/><rect x="9" y="9" width="6" height="6" rx="1"/></svg>`;
24602
+ const lineChartIcon = `<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="2,12 5,7 9,9 14,3"/></svg>`;
24603
+ const barChartIcon = `<svg viewBox="0 0 16 16" fill="currentColor"><rect x="1" y="9" width="3" height="6" rx="0.5"/><rect x="6" y="5" width="3" height="10" rx="0.5"/><rect x="11" y="7" width="3" height="8" rx="0.5"/></svg>`;
24490
24604
  return `
24491
24605
  <div id="${widgetId}" class="myio-chart-widget ${currentTheme === "dark" ? "dark" : ""} ${config.className || ""}">
24492
24606
  <div class="myio-chart-widget-header">
@@ -24495,18 +24609,16 @@ function createConsumptionChartWidget(config) {
24495
24609
  <button id="${widgetId}-settings-btn" class="myio-chart-widget-btn" title="Configura\xE7\xF5es">\u2699\uFE0F</button>
24496
24610
  ` : ""}
24497
24611
  <h4 id="${widgetId}-title" class="myio-chart-widget-title">${getTitle()}</h4>
24498
- </div>
24499
- <div class="myio-chart-widget-controls">
24500
24612
  ${showVizModeTabs ? `
24501
24613
  <div class="myio-chart-widget-tabs" id="${widgetId}-viz-tabs">
24502
- <button class="myio-chart-widget-tab ${currentVizMode === "total" ? "active" : ""}" data-viz="total">Consolidado</button>
24503
- <button class="myio-chart-widget-tab ${currentVizMode === "separate" ? "active" : ""}" data-viz="separate">Por Shopping</button>
24614
+ <button class="myio-chart-widget-tab icon-only ${currentVizMode === "total" ? "active" : ""}" data-viz="total" title="Consolidado">${consolidadoIcon}</button>
24615
+ <button class="myio-chart-widget-tab icon-only ${currentVizMode === "separate" ? "active" : ""}" data-viz="separate" title="Por Shopping">${porShoppingIcon}</button>
24504
24616
  </div>
24505
24617
  ` : ""}
24506
24618
  ${showChartTypeTabs ? `
24507
24619
  <div class="myio-chart-widget-tabs" id="${widgetId}-type-tabs">
24508
- <button class="myio-chart-widget-tab ${currentChartType === "line" ? "active" : ""}" data-type="line">Linhas</button>
24509
- <button class="myio-chart-widget-tab ${currentChartType === "bar" ? "active" : ""}" data-type="bar">Barras</button>
24620
+ <button class="myio-chart-widget-tab icon-only ${currentChartType === "line" ? "active" : ""}" data-type="line" title="Gr\xE1fico de Linhas">${lineChartIcon}</button>
24621
+ <button class="myio-chart-widget-tab icon-only ${currentChartType === "bar" ? "active" : ""}" data-type="bar" title="Gr\xE1fico de Barras">${barChartIcon}</button>
24510
24622
  </div>
24511
24623
  ` : ""}
24512
24624
  ${showMaximizeButton ? `
@@ -24543,19 +24655,22 @@ function createConsumptionChartWidget(config) {
24543
24655
  function renderSettingsModal() {
24544
24656
  const unit = config.unit ?? "";
24545
24657
  const isTemperature = config.domain === "temperature";
24658
+ const consolidadoIcon = `<svg viewBox="0 0 16 16" fill="currentColor" style="width:14px;height:14px;pointer-events:none"><rect x="3" y="3" width="10" height="10" rx="2"/></svg>`;
24659
+ const porShoppingIcon = `<svg viewBox="0 0 16 16" fill="currentColor" style="width:14px;height:14px;pointer-events:none"><rect x="1" y="1" width="6" height="6" rx="1"/><rect x="9" y="1" width="6" height="6" rx="1"/><rect x="1" y="9" width="6" height="6" rx="1"/><rect x="9" y="9" width="6" height="6" rx="1"/></svg>`;
24660
+ const lineChartIcon = `<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:14px;height:14px;pointer-events:none"><polyline points="2,12 5,7 9,9 14,3"/></svg>`;
24661
+ const barChartIcon = `<svg viewBox="0 0 16 16" fill="currentColor" style="width:14px;height:14px;pointer-events:none"><rect x="1" y="9" width="3" height="6" rx="0.5"/><rect x="6" y="5" width="3" height="10" rx="0.5"/><rect x="11" y="7" width="3" height="8" rx="0.5"/></svg>`;
24546
24662
  settingsHeaderInstance = createModalHeader({
24547
24663
  id: `${widgetId}-settings`,
24548
24664
  title: "Configura\xE7\xF5es",
24549
24665
  icon: "\u2699\uFE0F",
24550
24666
  theme: tempTheme,
24551
- backgroundColor: primaryColor,
24552
24667
  showThemeToggle: false,
24553
24668
  showMaximize: false,
24554
24669
  showClose: true,
24555
24670
  onClose: () => closeSettingsModal()
24556
24671
  });
24557
24672
  return `
24558
- <div id="${widgetId}-settings-overlay" class="myio-settings-overlay hidden">
24673
+ <div id="${widgetId}-settings-overlay" class="myio-settings-overlay myio-modal-scope hidden">
24559
24674
  <div class="myio-settings-card">
24560
24675
  ${settingsHeaderInstance.render()}
24561
24676
  <div class="myio-settings-body">
@@ -24566,13 +24681,8 @@ function createConsumptionChartWidget(config) {
24566
24681
  <div class="myio-settings-section-label">\u{1F4C5} Per\xEDodo</div>
24567
24682
  <div class="myio-settings-row">
24568
24683
  <div class="myio-settings-field" style="flex: 1;">
24569
- <select id="${widgetId}-settings-period" class="myio-settings-select">
24570
- <option value="7" ${tempPeriod === 7 ? "selected" : ""}>\xDAltimos 7 dias</option>
24571
- <option value="14" ${tempPeriod === 14 ? "selected" : ""}>\xDAltimos 14 dias</option>
24572
- <option value="30" ${tempPeriod === 30 ? "selected" : ""}>\xDAltimos 30 dias</option>
24573
- <option value="60" ${tempPeriod === 60 ? "selected" : ""}>\xDAltimos 60 dias</option>
24574
- <option value="90" ${tempPeriod === 90 ? "selected" : ""}>\xDAltimos 90 dias</option>
24575
- </select>
24684
+ <input type="text" id="${widgetId}-settings-daterange" class="myio-settings-input"
24685
+ readonly placeholder="Selecione o per\xEDodo..." style="cursor: pointer;">
24576
24686
  </div>
24577
24687
  </div>
24578
24688
  </div>
@@ -24701,8 +24811,8 @@ function createConsumptionChartWidget(config) {
24701
24811
  <div class="myio-settings-field" style="flex: 1; min-width: 180px;">
24702
24812
  <label class="myio-settings-field-label">Tipo de Gr\xE1fico</label>
24703
24813
  <div class="myio-settings-tabs" id="${widgetId}-settings-chart-type">
24704
- <button class="myio-settings-tab ${tempChartType === "line" ? "active" : ""}" data-type="line">\u{1F4C8} Linhas</button>
24705
- <button class="myio-settings-tab ${tempChartType === "bar" ? "active" : ""}" data-type="bar">\u{1F4CA} Barras</button>
24814
+ <button class="myio-settings-tab ${tempChartType === "line" ? "active" : ""}" data-type="line">${lineChartIcon} Linhas</button>
24815
+ <button class="myio-settings-tab ${tempChartType === "bar" ? "active" : ""}" data-type="bar">${barChartIcon} Barras</button>
24706
24816
  </div>
24707
24817
  </div>
24708
24818
 
@@ -24710,8 +24820,8 @@ function createConsumptionChartWidget(config) {
24710
24820
  <div class="myio-settings-field" style="flex: 1; min-width: 200px;">
24711
24821
  <label class="myio-settings-field-label">Agrupamento</label>
24712
24822
  <div class="myio-settings-tabs" id="${widgetId}-settings-viz-mode">
24713
- <button class="myio-settings-tab ${tempVizMode === "total" ? "active" : ""}" data-viz="total">\u{1F517} Consolidado</button>
24714
- <button class="myio-settings-tab ${tempVizMode === "separate" ? "active" : ""}" data-viz="separate">\u{1F3EC} Por Shopping</button>
24823
+ <button class="myio-settings-tab ${tempVizMode === "total" ? "active" : ""}" data-viz="total">${consolidadoIcon} Consolidado</button>
24824
+ <button class="myio-settings-tab ${tempVizMode === "separate" ? "active" : ""}" data-viz="separate">${porShoppingIcon} Por Shopping</button>
24715
24825
  </div>
24716
24826
  </div>
24717
24827
 
@@ -24853,18 +24963,21 @@ function createConsumptionChartWidget(config) {
24853
24963
  peakDateEl.textContent = peakDate;
24854
24964
  }
24855
24965
  }
24856
- function openSettingsModal() {
24966
+ async function openSettingsModal() {
24857
24967
  tempPeriod = currentPeriod;
24858
24968
  tempChartType = currentChartType;
24859
24969
  tempVizMode = currentVizMode;
24860
24970
  tempTheme = currentTheme;
24861
24971
  tempIdealRange = currentIdealRange ? { ...currentIdealRange } : null;
24972
+ dateRangePickerInstance = null;
24862
24973
  if (!settingsModalElement) {
24863
24974
  settingsModalElement = document.createElement("div");
24864
24975
  settingsModalElement.innerHTML = renderSettingsModal();
24865
24976
  document.body.appendChild(settingsModalElement.firstElementChild);
24866
24977
  settingsModalElement = document.getElementById(`${widgetId}-settings-overlay`);
24867
- setupSettingsModalListeners();
24978
+ await setupSettingsModalListeners();
24979
+ } else {
24980
+ await setupSettingsModalListeners();
24868
24981
  }
24869
24982
  updateSettingsModalValues();
24870
24983
  updateIdealRangeSuggestionTooltip();
@@ -24872,6 +24985,10 @@ function createConsumptionChartWidget(config) {
24872
24985
  }
24873
24986
  function closeSettingsModal() {
24874
24987
  settingsModalElement?.classList.add("hidden");
24988
+ if (dateRangePickerInstance) {
24989
+ dateRangePickerInstance.destroy();
24990
+ dateRangePickerInstance = null;
24991
+ }
24875
24992
  }
24876
24993
  function updateSettingsModalValues() {
24877
24994
  const periodSelect = document.getElementById(`${widgetId}-settings-period`);
@@ -24981,8 +25098,46 @@ function createConsumptionChartWidget(config) {
24981
25098
  label: "Faixa Sugerida"
24982
25099
  };
24983
25100
  }
24984
- function setupSettingsModalListeners() {
25101
+ async function setupSettingsModalListeners() {
24985
25102
  settingsHeaderInstance?.attachListeners();
25103
+ const dateRangeInput = document.getElementById(`${widgetId}-settings-daterange`);
25104
+ if (dateRangeInput && !dateRangePickerInstance) {
25105
+ try {
25106
+ const endDate = /* @__PURE__ */ new Date();
25107
+ const startDate = /* @__PURE__ */ new Date();
25108
+ startDate.setDate(endDate.getDate() - tempPeriod);
25109
+ const presetStart = tempStartDate || startDate.toISOString();
25110
+ const presetEnd = tempEndDate || endDate.toISOString();
25111
+ dateRangePickerInstance = await createDateRangePicker2(dateRangeInput, {
25112
+ presetStart,
25113
+ presetEnd,
25114
+ includeTime: true,
25115
+ timePrecision: "hour",
25116
+ maxRangeDays: 90,
25117
+ locale: "pt-BR",
25118
+ parentEl: document.getElementById(`${widgetId}-settings-overlay`),
25119
+ onApply: (result) => {
25120
+ tempStartDate = result.startISO;
25121
+ tempEndDate = result.endISO;
25122
+ const start = new Date(result.startISO);
25123
+ const end = new Date(result.endISO);
25124
+ const diffTime = Math.abs(end.getTime() - start.getTime());
25125
+ const diffHours = diffTime / (1e3 * 60 * 60);
25126
+ const diffDays = Math.ceil(diffTime / (1e3 * 60 * 60 * 24));
25127
+ tempPeriod = diffDays || 7;
25128
+ const granularitySelect = document.getElementById(`${widgetId}-settings-granularity`);
25129
+ if (granularitySelect && diffHours <= 48) {
25130
+ granularitySelect.value = "1h";
25131
+ const dayPeriodField = document.getElementById(`${widgetId}-settings-dayperiod-field`);
25132
+ if (dayPeriodField) dayPeriodField.style.display = "block";
25133
+ }
25134
+ console.log("[ConsumptionChartWidget] Date range applied:", { start: result.startISO, end: result.endISO, hours: diffHours, days: tempPeriod });
25135
+ }
25136
+ });
25137
+ } catch (error) {
25138
+ console.warn("[ConsumptionChartWidget] DateRangePicker initialization failed:", error);
25139
+ }
25140
+ }
24986
25141
  document.getElementById(`${widgetId}-settings-overlay`)?.addEventListener("click", (e) => {
24987
25142
  if (e.target.classList.contains("myio-settings-overlay")) {
24988
25143
  closeSettingsModal();
@@ -25070,13 +25225,56 @@ function createConsumptionChartWidget(config) {
25070
25225
  updateSettingsModalTabs();
25071
25226
  }
25072
25227
  });
25073
- document.getElementById(`${widgetId}-settings-reset`)?.addEventListener("click", () => {
25228
+ document.getElementById(`${widgetId}-settings-reset`)?.addEventListener("click", async () => {
25074
25229
  tempPeriod = config.defaultPeriod ?? 7;
25075
25230
  tempChartType = config.defaultChartType ?? "line";
25076
25231
  tempVizMode = config.defaultVizMode ?? "total";
25077
25232
  tempTheme = config.theme ?? "light";
25078
25233
  tempIdealRange = config.idealRange ?? null;
25079
- const granularitySelect = document.getElementById(`${widgetId}-settings-granularity`);
25234
+ tempStartDate = null;
25235
+ tempEndDate = null;
25236
+ if (dateRangePickerInstance) {
25237
+ dateRangePickerInstance.destroy();
25238
+ dateRangePickerInstance = null;
25239
+ }
25240
+ const dateRangeInput2 = document.getElementById(`${widgetId}-settings-daterange`);
25241
+ if (dateRangeInput2) {
25242
+ const endDate = /* @__PURE__ */ new Date();
25243
+ const startDate = /* @__PURE__ */ new Date();
25244
+ startDate.setDate(endDate.getDate() - tempPeriod);
25245
+ try {
25246
+ dateRangePickerInstance = await createDateRangePicker2(dateRangeInput2, {
25247
+ presetStart: startDate.toISOString(),
25248
+ presetEnd: endDate.toISOString(),
25249
+ includeTime: true,
25250
+ timePrecision: "hour",
25251
+ maxRangeDays: 90,
25252
+ locale: "pt-BR",
25253
+ parentEl: document.getElementById(`${widgetId}-settings-overlay`),
25254
+ onApply: (result) => {
25255
+ tempStartDate = result.startISO;
25256
+ tempEndDate = result.endISO;
25257
+ const start = new Date(result.startISO);
25258
+ const end = new Date(result.endISO);
25259
+ const diffTime = Math.abs(end.getTime() - start.getTime());
25260
+ const diffHours = diffTime / (1e3 * 60 * 60);
25261
+ const diffDays = Math.ceil(diffTime / (1e3 * 60 * 60 * 24));
25262
+ tempPeriod = diffDays || 7;
25263
+ const granularitySelect2 = document.getElementById(`${widgetId}-settings-granularity`);
25264
+ if (granularitySelect2 && diffHours <= 48) {
25265
+ granularitySelect2.value = "1h";
25266
+ const dayPeriodField2 = document.getElementById(`${widgetId}-settings-dayperiod-field`);
25267
+ if (dayPeriodField2) dayPeriodField2.style.display = "block";
25268
+ }
25269
+ }
25270
+ });
25271
+ } catch (error) {
25272
+ console.warn("[ConsumptionChartWidget] DateRangePicker reset failed:", error);
25273
+ }
25274
+ }
25275
+ const granularitySelect = document.getElementById(
25276
+ `${widgetId}-settings-granularity`
25277
+ );
25080
25278
  if (granularitySelect) granularitySelect.value = "1d";
25081
25279
  const dayPeriodField = document.getElementById(`${widgetId}-settings-dayperiod-field`);
25082
25280
  if (dayPeriodField) dayPeriodField.style.display = "none";
@@ -25222,6 +25420,10 @@ function createConsumptionChartWidget(config) {
25222
25420
  }
25223
25421
  settingsHeaderInstance?.destroy();
25224
25422
  settingsHeaderInstance = null;
25423
+ if (dateRangePickerInstance) {
25424
+ dateRangePickerInstance.destroy();
25425
+ dateRangePickerInstance = null;
25426
+ }
25225
25427
  if (settingsModalElement) {
25226
25428
  settingsModalElement.remove();
25227
25429
  settingsModalElement = null;
@@ -25673,6 +25875,581 @@ var EXPORT_DEFAULT_COLORS = DEFAULT_COLORS4;
25673
25875
  var EXPORT_DOMAIN_ICONS = DOMAIN_ICONS;
25674
25876
  var EXPORT_DOMAIN_LABELS = DOMAIN_LABELS;
25675
25877
  var EXPORT_DOMAIN_UNITS = DOMAIN_UNITS;
25878
+
25879
+ // src/components/DistributionChart/colorManager.ts
25880
+ var DEFAULT_SHOPPING_COLORS = [
25881
+ "#3b82f6",
25882
+ // Blue
25883
+ "#8b5cf6",
25884
+ // Purple
25885
+ "#f59e0b",
25886
+ // Amber
25887
+ "#ef4444",
25888
+ // Red
25889
+ "#10b981",
25890
+ // Emerald
25891
+ "#06b6d4",
25892
+ // Cyan
25893
+ "#ec4899",
25894
+ // Pink
25895
+ "#14b8a6",
25896
+ // Teal
25897
+ "#f97316",
25898
+ // Orange
25899
+ "#a855f7"
25900
+ // Violet
25901
+ ];
25902
+ var DEFAULT_ENERGY_GROUP_COLORS = {
25903
+ "Elevadores": "#3b82f6",
25904
+ "Escadas Rolantes": "#8b5cf6",
25905
+ "Climatiza\xE7\xE3o": "#f59e0b",
25906
+ "Climatizacao": "#f59e0b",
25907
+ // Without accent
25908
+ "Outros Equipamentos": "#ef4444",
25909
+ "Lojas": "#10b981"
25910
+ };
25911
+ var DEFAULT_WATER_GROUP_COLORS = {
25912
+ "Lojas": "#10b981",
25913
+ "\xC1rea Comum": "#0288d1",
25914
+ "Area Comum": "#0288d1"
25915
+ // Without accent
25916
+ };
25917
+ var DEFAULT_GAS_GROUP_COLORS = {
25918
+ "Cozinha": "#f59e0b",
25919
+ "Aquecimento": "#ef4444",
25920
+ "Outros": "#94a3b8"
25921
+ };
25922
+ function getDefaultGroupColors(domain) {
25923
+ switch (domain.toLowerCase()) {
25924
+ case "energy":
25925
+ return DEFAULT_ENERGY_GROUP_COLORS;
25926
+ case "water":
25927
+ return DEFAULT_WATER_GROUP_COLORS;
25928
+ case "gas":
25929
+ return DEFAULT_GAS_GROUP_COLORS;
25930
+ default:
25931
+ return DEFAULT_ENERGY_GROUP_COLORS;
25932
+ }
25933
+ }
25934
+ function assignShoppingColors(shoppingIds) {
25935
+ const colors = {};
25936
+ shoppingIds.forEach((id, index) => {
25937
+ colors[id] = DEFAULT_SHOPPING_COLORS[index % DEFAULT_SHOPPING_COLORS.length];
25938
+ });
25939
+ return colors;
25940
+ }
25941
+ function getShoppingColor(shoppingId, shoppingColors, fallbackIndex = 0) {
25942
+ if (shoppingColors && shoppingColors[shoppingId]) {
25943
+ return shoppingColors[shoppingId];
25944
+ }
25945
+ if (shoppingColors) {
25946
+ const normalizedId = shoppingId.toLowerCase();
25947
+ for (const [key, color] of Object.entries(shoppingColors)) {
25948
+ if (key.toLowerCase() === normalizedId || key.toLowerCase().includes(normalizedId)) {
25949
+ return color;
25950
+ }
25951
+ }
25952
+ }
25953
+ return DEFAULT_SHOPPING_COLORS[Math.abs(fallbackIndex) % DEFAULT_SHOPPING_COLORS.length];
25954
+ }
25955
+ function getGroupColor(groupName, groupColors, domain = "energy", fallbackIndex = 0) {
25956
+ if (groupColors && groupColors[groupName]) {
25957
+ return groupColors[groupName];
25958
+ }
25959
+ const defaultColors = getDefaultGroupColors(domain);
25960
+ if (defaultColors[groupName]) {
25961
+ return defaultColors[groupName];
25962
+ }
25963
+ return DEFAULT_SHOPPING_COLORS[Math.abs(fallbackIndex) % DEFAULT_SHOPPING_COLORS.length];
25964
+ }
25965
+ function getThemeColors2(theme) {
25966
+ if (theme === "dark") {
25967
+ return {
25968
+ text: "#f3f4f6",
25969
+ secondaryText: "#9ca3af",
25970
+ background: "#111827",
25971
+ cardBackground: "#1f2937",
25972
+ border: "#374151",
25973
+ grid: "#374151"
25974
+ };
25975
+ }
25976
+ return {
25977
+ text: "#1f2937",
25978
+ secondaryText: "#6b7280",
25979
+ background: "#f5f5f5",
25980
+ cardBackground: "#ffffff",
25981
+ border: "#e5e7eb",
25982
+ grid: "#e5e7eb"
25983
+ };
25984
+ }
25985
+ function getHashColor(str) {
25986
+ let hash = 0;
25987
+ for (let i = 0; i < str.length; i++) {
25988
+ const char = str.charCodeAt(i);
25989
+ hash = (hash << 5) - hash + char;
25990
+ hash = hash & hash;
25991
+ }
25992
+ return DEFAULT_SHOPPING_COLORS[Math.abs(hash) % DEFAULT_SHOPPING_COLORS.length];
25993
+ }
25994
+
25995
+ // src/components/DistributionChart/createDistributionChartWidget.ts
25996
+ var settingsIcon = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:16px;height:16px;pointer-events:none"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>`;
25997
+ var maximizeIcon = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:16px;height:16px;pointer-events:none"><polyline points="15 3 21 3 21 9"/><polyline points="9 21 3 21 3 15"/><line x1="21" y1="3" x2="14" y2="10"/><line x1="3" y1="21" x2="10" y2="14"/></svg>`;
25998
+ function createDistributionChartWidget(config) {
25999
+ const widgetId = `distribution-${config.domain}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
26000
+ let chartInstance = null;
26001
+ let currentMode = config.defaultMode || "groups";
26002
+ let currentTheme = config.theme || "light";
26003
+ let currentData = null;
26004
+ let containerElement = null;
26005
+ let isLoading = false;
26006
+ const title = config.title || getDomainTitle(config.domain);
26007
+ const chartHeight = config.chartHeight || 300;
26008
+ const showHeader = config.showHeader !== false;
26009
+ const showModeSelector = config.showModeSelector !== false;
26010
+ const showSettingsButton = config.showSettingsButton ?? false;
26011
+ const showMaximizeButton = config.showMaximizeButton ?? false;
26012
+ const decimalPlaces = config.decimalPlaces ?? 2;
26013
+ const modes = config.modes || getDefaultModes(config.domain);
26014
+ const groupColors = config.groupColors || getDefaultGroupColors(config.domain);
26015
+ function getDomainTitle(domain) {
26016
+ const titles = {
26017
+ energy: "Distribui\xE7\xE3o de Energia",
26018
+ water: "Distribui\xE7\xE3o de \xC1gua",
26019
+ gas: "Distribui\xE7\xE3o de G\xE1s",
26020
+ temperature: "Distribui\xE7\xE3o de Temperatura"
26021
+ };
26022
+ return titles[domain.toLowerCase()] || `Distribui\xE7\xE3o de ${domain}`;
26023
+ }
26024
+ function getDefaultModes(domain) {
26025
+ if (domain === "water") {
26026
+ return [
26027
+ { value: "groups", label: "Lojas vs \xC1rea Comum" },
26028
+ { value: "stores", label: "Lojas por Shopping" },
26029
+ { value: "common", label: "\xC1rea Comum por Shopping" }
26030
+ ];
26031
+ }
26032
+ return [
26033
+ { value: "groups", label: "Por Grupos de Equipamentos" },
26034
+ { value: "elevators", label: "Elevadores por Shopping" },
26035
+ { value: "escalators", label: "Escadas Rolantes por Shopping" },
26036
+ { value: "hvac", label: "Climatiza\xE7\xE3o por Shopping" },
26037
+ { value: "others", label: "Outros Equipamentos por Shopping" },
26038
+ { value: "stores", label: "Lojas por Shopping" }
26039
+ ];
26040
+ }
26041
+ function $id(id) {
26042
+ if (config.$container) {
26043
+ return config.$container[0].querySelector(`#${id}`);
26044
+ }
26045
+ return document.getElementById(id);
26046
+ }
26047
+ function formatValue(value) {
26048
+ if (config.unitLarge && config.thresholdForLargeUnit && value >= config.thresholdForLargeUnit) {
26049
+ return `${(value / config.thresholdForLargeUnit).toFixed(decimalPlaces)} ${config.unitLarge}`;
26050
+ }
26051
+ return `${value.toFixed(decimalPlaces)} ${config.unit}`;
26052
+ }
26053
+ function getColor(key, index, isGroupMode2) {
26054
+ if (isGroupMode2) {
26055
+ return getGroupColor(key, groupColors, config.domain, index);
26056
+ }
26057
+ const shoppingColors = config.getShoppingColors?.();
26058
+ return getShoppingColor(key, shoppingColors, index);
26059
+ }
26060
+ function getColors2() {
26061
+ return getThemeColors2(currentTheme);
26062
+ }
26063
+ function isGroupMode() {
26064
+ return currentMode === "groups";
26065
+ }
26066
+ function renderHTML() {
26067
+ const colors = getColors2();
26068
+ const modeOptions = modes.map(
26069
+ (m) => `<option value="${m.value}" ${m.value === currentMode ? "selected" : ""}>${m.label}</option>`
26070
+ ).join("");
26071
+ const headerButtons = [];
26072
+ if (showSettingsButton) {
26073
+ headerButtons.push(`
26074
+ <button id="${widgetId}-settings-btn" class="myio-dist-btn" title="Configura\xE7\xF5es">
26075
+ ${settingsIcon}
26076
+ </button>
26077
+ `);
26078
+ }
26079
+ if (showMaximizeButton) {
26080
+ headerButtons.push(`
26081
+ <button id="${widgetId}-maximize-btn" class="myio-dist-btn" title="Expandir">
26082
+ ${maximizeIcon}
26083
+ </button>
26084
+ `);
26085
+ }
26086
+ return `
26087
+ <style>
26088
+ #${widgetId} {
26089
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
26090
+ }
26091
+ #${widgetId} .myio-dist-header {
26092
+ display: flex;
26093
+ justify-content: space-between;
26094
+ align-items: center;
26095
+ margin-bottom: 16px;
26096
+ flex-wrap: wrap;
26097
+ gap: 12px;
26098
+ }
26099
+ #${widgetId} .myio-dist-title {
26100
+ margin: 0;
26101
+ font-size: 16px;
26102
+ font-weight: 600;
26103
+ color: ${colors.text};
26104
+ }
26105
+ #${widgetId} .myio-dist-controls {
26106
+ display: flex;
26107
+ align-items: center;
26108
+ gap: 8px;
26109
+ }
26110
+ #${widgetId} .myio-dist-label {
26111
+ font-size: 12px;
26112
+ color: ${colors.secondaryText};
26113
+ }
26114
+ #${widgetId} .myio-dist-select {
26115
+ padding: 6px 10px;
26116
+ border-radius: 6px;
26117
+ border: 1px solid ${colors.border};
26118
+ background: ${colors.cardBackground};
26119
+ color: ${colors.text};
26120
+ font-size: 12px;
26121
+ cursor: pointer;
26122
+ min-width: 180px;
26123
+ }
26124
+ #${widgetId} .myio-dist-select:focus {
26125
+ outline: none;
26126
+ border-color: #3e1a7d;
26127
+ }
26128
+ #${widgetId} .myio-dist-btn {
26129
+ display: flex;
26130
+ align-items: center;
26131
+ justify-content: center;
26132
+ padding: 6px 8px;
26133
+ border: 1px solid ${colors.border};
26134
+ border-radius: 6px;
26135
+ background: transparent;
26136
+ color: ${colors.text};
26137
+ cursor: pointer;
26138
+ transition: all 0.2s;
26139
+ }
26140
+ #${widgetId} .myio-dist-btn:hover {
26141
+ background: #3e1a7d;
26142
+ border-color: #3e1a7d;
26143
+ color: white;
26144
+ }
26145
+ #${widgetId} .myio-dist-chart-container {
26146
+ position: relative;
26147
+ height: ${chartHeight}px;
26148
+ }
26149
+ #${widgetId} .myio-dist-loading {
26150
+ position: absolute;
26151
+ top: 0;
26152
+ left: 0;
26153
+ right: 0;
26154
+ bottom: 0;
26155
+ display: flex;
26156
+ align-items: center;
26157
+ justify-content: center;
26158
+ background: ${colors.cardBackground}ee;
26159
+ z-index: 10;
26160
+ }
26161
+ #${widgetId} .myio-dist-spinner {
26162
+ width: 32px;
26163
+ height: 32px;
26164
+ border: 3px solid ${colors.border};
26165
+ border-top-color: #3e1a7d;
26166
+ border-radius: 50%;
26167
+ animation: myio-dist-spin 0.8s linear infinite;
26168
+ }
26169
+ @keyframes myio-dist-spin {
26170
+ to { transform: rotate(360deg); }
26171
+ }
26172
+ #${widgetId} .myio-dist-empty {
26173
+ display: flex;
26174
+ flex-direction: column;
26175
+ align-items: center;
26176
+ justify-content: center;
26177
+ height: 100%;
26178
+ color: ${colors.secondaryText};
26179
+ font-size: 14px;
26180
+ }
26181
+ #${widgetId} .myio-dist-empty-icon {
26182
+ font-size: 48px;
26183
+ margin-bottom: 12px;
26184
+ opacity: 0.5;
26185
+ }
26186
+ </style>
26187
+
26188
+ <div id="${widgetId}" class="myio-distribution-widget" style="
26189
+ background: ${colors.cardBackground};
26190
+ border-radius: 12px;
26191
+ padding: 16px;
26192
+ height: 100%;
26193
+ display: flex;
26194
+ flex-direction: column;
26195
+ ">
26196
+ ${showHeader ? `
26197
+ <div class="myio-dist-header">
26198
+ <h4 class="myio-dist-title">${title}</h4>
26199
+ <div class="myio-dist-controls">
26200
+ ${showModeSelector && modes.length > 1 ? `
26201
+ <label for="${widgetId}-mode" class="myio-dist-label">Visualizar:</label>
26202
+ <select id="${widgetId}-mode" class="myio-dist-select">
26203
+ ${modeOptions}
26204
+ </select>
26205
+ ` : ""}
26206
+ ${headerButtons.join("")}
26207
+ </div>
26208
+ </div>
26209
+ ` : ""}
26210
+
26211
+ <div class="myio-dist-chart-container">
26212
+ <canvas id="${widgetId}-canvas"></canvas>
26213
+ <div id="${widgetId}-loading" class="myio-dist-loading" style="display: none;">
26214
+ <div class="myio-dist-spinner"></div>
26215
+ </div>
26216
+ </div>
26217
+ </div>
26218
+ `;
26219
+ }
26220
+ function setLoading(loading) {
26221
+ isLoading = loading;
26222
+ const loadingEl = $id(`${widgetId}-loading`);
26223
+ if (loadingEl) {
26224
+ loadingEl.style.display = loading ? "flex" : "none";
26225
+ }
26226
+ }
26227
+ function buildChartData(distribution) {
26228
+ const labels = [];
26229
+ const data = [];
26230
+ const backgroundColors = [];
26231
+ const total = Object.values(distribution).reduce((sum, val) => sum + val, 0);
26232
+ const isGroup = isGroupMode();
26233
+ const entries = Object.entries(distribution).filter(([_, value]) => value > 0).sort((a, b) => b[1] - a[1]);
26234
+ entries.forEach(([key, value], index) => {
26235
+ const percentage = total > 0 ? (value / total * 100).toFixed(1) : "0";
26236
+ labels.push(`${key} (${formatValue(value)} - ${percentage}%)`);
26237
+ data.push(value);
26238
+ backgroundColors.push(getColor(key, index, isGroup));
26239
+ });
26240
+ return { labels, data, backgroundColors, total };
26241
+ }
26242
+ function renderEmptyState() {
26243
+ const container = $id(`${widgetId}-canvas`)?.parentElement;
26244
+ if (container) {
26245
+ const emptyEl = document.createElement("div");
26246
+ emptyEl.className = "myio-dist-empty";
26247
+ emptyEl.innerHTML = `
26248
+ <div class="myio-dist-empty-icon">\u{1F4CA}</div>
26249
+ <div>Sem dados dispon\xEDveis</div>
26250
+ `;
26251
+ const canvas = $id(`${widgetId}-canvas`);
26252
+ if (canvas) canvas.style.display = "none";
26253
+ const existingEmpty = container.querySelector(".myio-dist-empty");
26254
+ if (!existingEmpty) {
26255
+ container.appendChild(emptyEl);
26256
+ }
26257
+ }
26258
+ }
26259
+ function removeEmptyState() {
26260
+ const container = $id(`${widgetId}-canvas`)?.parentElement;
26261
+ if (container) {
26262
+ const emptyEl = container.querySelector(".myio-dist-empty");
26263
+ if (emptyEl) emptyEl.remove();
26264
+ const canvas = $id(`${widgetId}-canvas`);
26265
+ if (canvas) canvas.style.display = "block";
26266
+ }
26267
+ }
26268
+ async function updateChart() {
26269
+ const canvas = $id(`${widgetId}-canvas`);
26270
+ if (!canvas) {
26271
+ console.error(`[${config.domain.toUpperCase()}] Distribution canvas not found`);
26272
+ return;
26273
+ }
26274
+ setLoading(true);
26275
+ try {
26276
+ const distribution = await config.fetchDistribution(currentMode);
26277
+ if (!distribution || Object.keys(distribution).length === 0) {
26278
+ console.warn(`[${config.domain.toUpperCase()}] No distribution data for mode: ${currentMode}`);
26279
+ currentData = null;
26280
+ setLoading(false);
26281
+ renderEmptyState();
26282
+ return;
26283
+ }
26284
+ removeEmptyState();
26285
+ currentData = distribution;
26286
+ const { labels, data, backgroundColors, total } = buildChartData(distribution);
26287
+ const colors = getColors2();
26288
+ const Chart2 = window.Chart;
26289
+ if (!Chart2) {
26290
+ throw new Error("Chart.js not loaded");
26291
+ }
26292
+ if (chartInstance) {
26293
+ chartInstance.destroy();
26294
+ chartInstance = null;
26295
+ }
26296
+ const ctx = canvas.getContext("2d");
26297
+ if (!ctx) {
26298
+ throw new Error("Could not get canvas context");
26299
+ }
26300
+ chartInstance = new Chart2(ctx, {
26301
+ type: "bar",
26302
+ data: {
26303
+ labels,
26304
+ datasets: [
26305
+ {
26306
+ label: `Consumo (${config.unit})`,
26307
+ data,
26308
+ backgroundColor: backgroundColors
26309
+ }
26310
+ ]
26311
+ },
26312
+ options: {
26313
+ responsive: true,
26314
+ maintainAspectRatio: false,
26315
+ indexAxis: "y",
26316
+ // Horizontal bar chart
26317
+ animation: false,
26318
+ plugins: {
26319
+ legend: { display: false },
26320
+ tooltip: {
26321
+ callbacks: {
26322
+ label: (context) => {
26323
+ const value = context.parsed.x || 0;
26324
+ const percentage = total > 0 ? (value / total * 100).toFixed(1) : "0";
26325
+ return `${formatValue(value)} (${percentage}%)`;
26326
+ }
26327
+ }
26328
+ }
26329
+ },
26330
+ scales: {
26331
+ x: {
26332
+ beginAtZero: true,
26333
+ ticks: {
26334
+ callback: (value) => formatValue(Number(value)),
26335
+ color: colors.secondaryText,
26336
+ font: { size: 11 }
26337
+ },
26338
+ grid: { color: colors.grid }
26339
+ },
26340
+ y: {
26341
+ ticks: {
26342
+ font: { size: 11 },
26343
+ color: colors.text
26344
+ },
26345
+ grid: { display: false }
26346
+ }
26347
+ }
26348
+ }
26349
+ });
26350
+ config.onDataLoaded?.(distribution);
26351
+ console.log(`[${config.domain.toUpperCase()}] Distribution chart updated for mode: ${currentMode}`);
26352
+ } catch (error) {
26353
+ console.error(`[${config.domain.toUpperCase()}] Error updating distribution chart:`, error);
26354
+ config.onError?.(error);
26355
+ renderEmptyState();
26356
+ } finally {
26357
+ setLoading(false);
26358
+ }
26359
+ }
26360
+ function setupListeners() {
26361
+ const modeSelect = $id(`${widgetId}-mode`);
26362
+ if (modeSelect) {
26363
+ modeSelect.addEventListener("change", async (e) => {
26364
+ currentMode = e.target.value;
26365
+ config.onModeChange?.(currentMode);
26366
+ await updateChart();
26367
+ });
26368
+ }
26369
+ if (showSettingsButton) {
26370
+ const settingsBtn = $id(`${widgetId}-settings-btn`);
26371
+ if (settingsBtn) {
26372
+ settingsBtn.addEventListener("click", () => {
26373
+ config.onSettingsClick?.();
26374
+ });
26375
+ }
26376
+ }
26377
+ if (showMaximizeButton) {
26378
+ const maximizeBtn = $id(`${widgetId}-maximize-btn`);
26379
+ if (maximizeBtn) {
26380
+ maximizeBtn.addEventListener("click", () => {
26381
+ config.onMaximizeClick?.();
26382
+ });
26383
+ }
26384
+ }
26385
+ }
26386
+ function updateThemeStyles() {
26387
+ const colors = getColors2();
26388
+ const widget = $id(widgetId);
26389
+ if (widget) {
26390
+ widget.style.background = colors.cardBackground;
26391
+ const title2 = widget.querySelector(".myio-dist-title");
26392
+ if (title2) title2.style.color = colors.text;
26393
+ const labels = widget.querySelectorAll(".myio-dist-label");
26394
+ labels.forEach((l) => l.style.color = colors.secondaryText);
26395
+ const select = widget.querySelector(".myio-dist-select");
26396
+ if (select) {
26397
+ select.style.background = colors.cardBackground;
26398
+ select.style.color = colors.text;
26399
+ select.style.borderColor = colors.border;
26400
+ }
26401
+ const buttons = widget.querySelectorAll(".myio-dist-btn");
26402
+ buttons.forEach((b) => {
26403
+ b.style.color = colors.text;
26404
+ b.style.borderColor = colors.border;
26405
+ });
26406
+ }
26407
+ }
26408
+ const instance = {
26409
+ async render() {
26410
+ containerElement = $id(config.containerId);
26411
+ if (!containerElement) {
26412
+ throw new Error(`Container #${config.containerId} not found`);
26413
+ }
26414
+ containerElement.innerHTML = renderHTML();
26415
+ setupListeners();
26416
+ await updateChart();
26417
+ },
26418
+ async setMode(mode) {
26419
+ currentMode = mode;
26420
+ const modeSelect = $id(`${widgetId}-mode`);
26421
+ if (modeSelect) {
26422
+ modeSelect.value = mode;
26423
+ }
26424
+ config.onModeChange?.(mode);
26425
+ await updateChart();
26426
+ },
26427
+ async refresh() {
26428
+ await updateChart();
26429
+ },
26430
+ setTheme(theme) {
26431
+ currentTheme = theme;
26432
+ updateThemeStyles();
26433
+ if (currentData) {
26434
+ updateChart();
26435
+ }
26436
+ },
26437
+ destroy() {
26438
+ if (chartInstance) {
26439
+ chartInstance.destroy();
26440
+ chartInstance = null;
26441
+ }
26442
+ if (containerElement) {
26443
+ containerElement.innerHTML = "";
26444
+ }
26445
+ currentData = null;
26446
+ },
26447
+ getChartInstance: () => chartInstance,
26448
+ getCurrentMode: () => currentMode,
26449
+ getCurrentData: () => currentData
26450
+ };
26451
+ return instance;
26452
+ }
25676
26453
  // Annotate the CommonJS export names for ESM import in node:
25677
26454
  0 && (module.exports = {
25678
26455
  CHART_COLORS,
@@ -25681,6 +26458,10 @@ var EXPORT_DOMAIN_UNITS = DOMAIN_UNITS;
25681
26458
  CONSUMPTION_THEME_COLORS,
25682
26459
  ConnectionStatusType,
25683
26460
  DEFAULT_CLAMP_RANGE,
26461
+ DEFAULT_ENERGY_GROUP_COLORS,
26462
+ DEFAULT_GAS_GROUP_COLORS,
26463
+ DEFAULT_SHOPPING_COLORS,
26464
+ DEFAULT_WATER_GROUP_COLORS,
25684
26465
  DeviceStatusType,
25685
26466
  EXPORT_DEFAULT_COLORS,
25686
26467
  EXPORT_DOMAIN_ICONS,
@@ -25694,6 +26475,7 @@ var EXPORT_DOMAIN_UNITS = DOMAIN_UNITS;
25694
26475
  addDetectionContext,
25695
26476
  addNamespace,
25696
26477
  aggregateByDay,
26478
+ assignShoppingColors,
25697
26479
  averageByDay,
25698
26480
  buildListItemsThingsboardByUniqueDatasource,
25699
26481
  buildMyioIngestionAuth,
@@ -25715,6 +26497,7 @@ var EXPORT_DOMAIN_UNITS = DOMAIN_UNITS;
25715
26497
  createConsumptionChartWidget,
25716
26498
  createConsumptionModal,
25717
26499
  createDateRangePicker,
26500
+ createDistributionChartWidget,
25718
26501
  createInputDateRangePickerInsideDIV,
25719
26502
  createModalHeader,
25720
26503
  decodePayload,
@@ -25753,11 +26536,16 @@ var EXPORT_DOMAIN_UNITS = DOMAIN_UNITS;
25753
26536
  getAvailableContexts,
25754
26537
  getConnectionStatusIcon,
25755
26538
  getDateRangeArray,
26539
+ getDefaultGroupColors,
25756
26540
  getDeviceStatusIcon,
25757
26541
  getDeviceStatusInfo,
26542
+ getDistributionThemeColors,
26543
+ getGroupColor,
26544
+ getHashColor,
25758
26545
  getModalHeaderStyles,
25759
26546
  getSaoPauloISOString,
25760
26547
  getSaoPauloISOStringFixed,
26548
+ getShoppingColor,
25761
26549
  getValueByDatakey,
25762
26550
  getValueByDatakeyLegacy,
25763
26551
  getWaterCategories,