myio-js-library 0.1.529 → 0.1.530
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 +2835 -130
- package/dist/index.d.cts +1938 -6
- package/dist/index.d.ts +1938 -6
- package/dist/index.js +2752 -119
- package/dist/myio-js-library.umd.js +2750 -119
- package/dist/myio-js-library.umd.min.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -63,6 +63,7 @@ __export(src_exports, {
|
|
|
63
63
|
CONSUMPTION_CHART_COLORS: () => DEFAULT_COLORS,
|
|
64
64
|
CONSUMPTION_CHART_DEFAULTS: () => DEFAULT_CONFIG,
|
|
65
65
|
CONSUMPTION_THEME_COLORS: () => THEME_COLORS2,
|
|
66
|
+
COVERAGE_STYLE_ID: () => COVERAGE_STYLE_ID,
|
|
66
67
|
CUSTOMER_CODE_RE: () => CUSTOMER_CODE_RE,
|
|
67
68
|
CUSTOMER_NAME_STOPWORDS: () => CUSTOMER_NAME_STOPWORDS,
|
|
68
69
|
CardGridPanel: () => CardGridPanel,
|
|
@@ -130,6 +131,7 @@ __export(src_exports, {
|
|
|
130
131
|
DEFAULT_SWITCH_STATE: () => DEFAULT_SWITCH_STATE,
|
|
131
132
|
DEFAULT_TABS: () => DEFAULT_TABS,
|
|
132
133
|
DEFAULT_WATER_GROUP_COLORS: () => DEFAULT_WATER_GROUP_COLORS,
|
|
134
|
+
DEVICE_CATEGORY_STYLE_ID: () => DEVICE_CATEGORY_STYLE_ID,
|
|
133
135
|
DEVICE_COUNT_KEYS: () => DEVICE_COUNT_KEYS,
|
|
134
136
|
DEVICE_OPERATIONAL_CARD_GRID_STYLES: () => DEVICE_OPERATIONAL_CARD_GRID_STYLES,
|
|
135
137
|
DEVICE_OPERATIONAL_CARD_STYLES: () => DEVICE_OPERATIONAL_CARD_STYLES,
|
|
@@ -141,6 +143,7 @@ __export(src_exports, {
|
|
|
141
143
|
DOMAIN_CODES: () => DOMAIN_CODES,
|
|
142
144
|
DOMAIN_MAP: () => DOMAIN_MAP,
|
|
143
145
|
DeviceCategory: () => DeviceCategory,
|
|
146
|
+
DeviceCategoryConflictError: () => DeviceCategoryConflictError,
|
|
144
147
|
DeviceComparisonTooltip: () => DeviceComparisonTooltip,
|
|
145
148
|
DeviceContextType: () => ContextType,
|
|
146
149
|
DeviceDomainType: () => DomainType2,
|
|
@@ -188,6 +191,8 @@ __export(src_exports, {
|
|
|
188
191
|
GRANULARITY_SELECTOR_CSS_PREFIX: () => GRANULARITY_SELECTOR_CSS_PREFIX,
|
|
189
192
|
GRID_SORT_OPTIONS: () => GRID_SORT_OPTIONS,
|
|
190
193
|
GoalsModal: () => GoalsModal,
|
|
194
|
+
GoalsMoneyApiError: () => GoalsMoneyApiError,
|
|
195
|
+
GoalsMoneyClient: () => GoalsMoneyClient,
|
|
191
196
|
HEADER_CSS_PREFIX: () => HEADER_CSS_PREFIX,
|
|
192
197
|
HEADER_DEFAULT_CARD_COLORS: () => DEFAULT_CARD_COLORS,
|
|
193
198
|
HEADER_DEFAULT_CONFIG_TEMPLATE: () => HEADER_DEFAULT_CONFIG_TEMPLATE,
|
|
@@ -215,6 +220,9 @@ __export(src_exports, {
|
|
|
215
220
|
MEASUREMENT_DOMAIN_CONFIG: () => DOMAIN_CONFIG5,
|
|
216
221
|
MENU_SHOPPING_CSS_PREFIX: () => MENU_SHOPPING_CSS_PREFIX,
|
|
217
222
|
METRO_TILE_COLORS: () => METRO_TILE_COLORS,
|
|
223
|
+
MONEY_DASH: () => DASH,
|
|
224
|
+
MONEY_REQUIRES_DEVICE_GRANULARITY: () => MONEY_REQUIRES_DEVICE_GRANULARITY,
|
|
225
|
+
MONEY_VARIANCE_HEADER: () => MONEY_VARIANCE_HEADER,
|
|
218
226
|
MOTOR_SORT_OPTIONS: () => MOTOR_SORT_OPTIONS,
|
|
219
227
|
MYIO_CHART_PALETTE: () => MYIO_CHART_PALETTE,
|
|
220
228
|
MYIO_CHART_PALETTE_DARK: () => MYIO_CHART_PALETTE_DARK,
|
|
@@ -259,6 +267,7 @@ __export(src_exports, {
|
|
|
259
267
|
POWER_LIMITS_DEVICE_TYPES: () => DEVICE_TYPES,
|
|
260
268
|
POWER_LIMITS_STATUS_CONFIG: () => STATUS_CONFIG,
|
|
261
269
|
POWER_LIMITS_TELEMETRY_TYPES: () => TELEMETRY_TYPES2,
|
|
270
|
+
REPORT_MONEY_HEADER: () => REPORT_MONEY_HEADER,
|
|
262
271
|
SCHEDULE_HOLIDAY_CSS_PREFIX: () => SCHEDULE_HOLIDAY_CSS_PREFIX,
|
|
263
272
|
SCHEDULE_IR_CSS_PREFIX: () => SCHEDULE_IR_CSS_PREFIX,
|
|
264
273
|
SCHEDULE_ON_OFF_CSS_PREFIX: () => SCHEDULE_ON_OFF_CSS_PREFIX,
|
|
@@ -300,6 +309,9 @@ __export(src_exports, {
|
|
|
300
309
|
TELEMETRY_INFO_WATER_CATEGORY_CONFIG: () => WATER_CATEGORY_CONFIG,
|
|
301
310
|
TEMPERATURE_SORT_OPTIONS: () => TEMPERATURE_SORT_OPTIONS,
|
|
302
311
|
TEMPERATURE_UNITS: () => TEMPERATURE_UNITS,
|
|
312
|
+
TariffApiAdapter: () => TariffApiAdapter,
|
|
313
|
+
TariffApiClient: () => TariffApiClient,
|
|
314
|
+
TariffApiError: () => TariffApiError,
|
|
303
315
|
TelemetryGridController: () => TelemetryGridController,
|
|
304
316
|
TelemetryGridView: () => TelemetryGridView,
|
|
305
317
|
TempComparisonTooltip: () => TempComparisonTooltip,
|
|
@@ -307,6 +319,10 @@ __export(src_exports, {
|
|
|
307
319
|
TempSensorSummaryTooltip: () => TempSensorSummaryTooltip,
|
|
308
320
|
Temperature: () => Temperature,
|
|
309
321
|
UsersSummaryTooltip: () => UsersSummaryTooltip,
|
|
322
|
+
VARIANCE_LABEL_ABOVE: () => VARIANCE_LABEL_ABOVE,
|
|
323
|
+
VARIANCE_LABEL_BELOW: () => VARIANCE_LABEL_BELOW,
|
|
324
|
+
VARIANCE_LABEL_ONTARGET: () => VARIANCE_LABEL_ONTARGET,
|
|
325
|
+
VARIANCE_LABEL_WITHHELD: () => VARIANCE_LABEL_WITHHELD,
|
|
310
326
|
VirtualList: () => VirtualList,
|
|
311
327
|
WAITING_STATUSES: () => WAITING_STATUSES,
|
|
312
328
|
WATER_DEVICE_CATEGORIES: () => WATER_DEVICE_CATEGORIES,
|
|
@@ -332,15 +348,20 @@ __export(src_exports, {
|
|
|
332
348
|
buildAnnotationServiceOrchestrator: () => buildAnnotationServiceOrchestrator,
|
|
333
349
|
buildAnnotationsCsv: () => buildAnnotationsCsv,
|
|
334
350
|
buildAnnotationsExportFilename: () => buildExportFilename,
|
|
351
|
+
buildBudgetHTML: () => buildBudgetHTML,
|
|
335
352
|
buildByStatusFromDevices: () => buildByStatusFromDevices,
|
|
353
|
+
buildCoverageHTML: () => buildCoverageHTML,
|
|
336
354
|
buildCoverageWarningTextPtBR: () => buildCoverageWarningTextPtBR,
|
|
337
355
|
buildDeviceGridEntityObject: () => buildEntityObject,
|
|
338
356
|
buildEquipmentCategoryDataForTooltip: () => buildEquipmentCategoryDataForTooltip,
|
|
339
357
|
buildEquipmentCategorySummary: () => buildEquipmentCategorySummary,
|
|
358
|
+
buildFinancialRowHTML: () => buildFinancialRowHTML,
|
|
340
359
|
buildListItemsThingsboardByUniqueDatasource: () => buildListItemsThingsboardByUniqueDatasource,
|
|
360
|
+
buildMoneyVarianceHTML: () => buildMoneyVarianceHTML,
|
|
341
361
|
buildMyioIngestionAuth: () => buildMyioIngestionAuth,
|
|
342
362
|
buildTemplateExport: () => buildTemplateExport,
|
|
343
363
|
buildTicketServiceOrchestrator: () => buildTicketServiceOrchestrator,
|
|
364
|
+
buildVerdictHTML: () => buildVerdictHTML,
|
|
344
365
|
buildWaterReportCSV: () => buildWaterReportCSV,
|
|
345
366
|
buildWaterStoresCSV: () => buildWaterStoresCSV,
|
|
346
367
|
calcDeltaPercent: () => calcDeltaPercent,
|
|
@@ -361,6 +382,7 @@ __export(src_exports, {
|
|
|
361
382
|
calculateStats: () => calculateStats,
|
|
362
383
|
canEditAlarmRules: () => canEditAlarmRules,
|
|
363
384
|
canModifyAnnotation: () => canModifyAnnotation,
|
|
385
|
+
centsToDecimalString: () => centsToDecimalString,
|
|
364
386
|
checkCustomerCodeAvailable: () => checkCustomerCodeAvailable,
|
|
365
387
|
clampTemperature: () => clampTemperature,
|
|
366
388
|
classify: () => classify,
|
|
@@ -372,9 +394,14 @@ __export(src_exports, {
|
|
|
372
394
|
clearAllAuthCaches: () => clearAllAuthCaches,
|
|
373
395
|
clearFreshdeskTicketsOnTB: () => clearFreshdeskTicketsOnTB,
|
|
374
396
|
closeAnnotationsExportModal: () => closeExportModal,
|
|
397
|
+
collapseHoursToBands: () => collapseHoursToBands,
|
|
398
|
+
collapseTreeToBands: () => collapseTreeToBands,
|
|
375
399
|
collectDeviceOverrides: () => collectDeviceOverrides,
|
|
376
400
|
computeBaseGroupResidual: () => computeBaseGroupResidual,
|
|
401
|
+
computeDeltaPct: () => computeDeltaPct,
|
|
402
|
+
computeMoneyVariance: () => computeMoneyVariance,
|
|
377
403
|
connectionStatusIcons: () => connectionStatusIcons,
|
|
404
|
+
coveragePercentLabel: () => coveragePercentLabel,
|
|
378
405
|
createActionButton: () => createActionButton,
|
|
379
406
|
createAlarmCardElement: () => createAlarmCardElement,
|
|
380
407
|
createAlarmsNotificationsPanelComponent: () => createAlarmsNotificationsPanelComponent,
|
|
@@ -387,6 +414,7 @@ __export(src_exports, {
|
|
|
387
414
|
createConsumption7DaysChart: () => createConsumption7DaysChart,
|
|
388
415
|
createConsumptionChartWidget: () => createConsumptionChartWidget,
|
|
389
416
|
createConsumptionModal: () => createConsumptionModal,
|
|
417
|
+
createCoverageDeepLink: () => createCoverageDeepLink,
|
|
390
418
|
createCsvButton: () => createCsvButton,
|
|
391
419
|
createCustomerCardV1: () => createCustomerCardV1,
|
|
392
420
|
createCustomerCardV2: () => createCustomerCardV2,
|
|
@@ -406,16 +434,19 @@ __export(src_exports, {
|
|
|
406
434
|
createEnergyPanelComponent: () => createEnergyPanelComponent,
|
|
407
435
|
createErrorSpan: () => createErrorSpan,
|
|
408
436
|
createExportButton: () => createExportButton,
|
|
437
|
+
createFakeDeviceCategoryPort: () => createFakeDeviceCategoryPort,
|
|
409
438
|
createFancoilRemote: () => createFancoilRemote,
|
|
410
439
|
createFilterModalComponent: () => createFilterModalComponent,
|
|
411
440
|
createFooterComponent: () => createFooterComponent,
|
|
412
441
|
createFreshdeskTicket: () => createTicket,
|
|
413
442
|
createGoalsBarTooltip: () => createGoalsBarTooltip,
|
|
443
|
+
createGoalsMoneyClient: () => createGoalsMoneyClient,
|
|
414
444
|
createGranularitySelector: () => createGranularitySelector,
|
|
415
445
|
createGroupScheduleCard: () => createGroupScheduleCard,
|
|
416
446
|
createHeaderComponent: () => createHeaderComponent,
|
|
417
447
|
createHeaderDevicesGridComponent: () => createHeaderDevicesGridComponent,
|
|
418
448
|
createHeaderShoppingComponent: () => createHeaderShoppingComponent,
|
|
449
|
+
createHttpDeviceCategoryPort: () => createHttpDeviceCategoryPort,
|
|
419
450
|
createImgGallery: () => createImgGallery,
|
|
420
451
|
createInputDateRangePickerInsideDIV: () => createInputDateRangePickerInsideDIV,
|
|
421
452
|
createLibraryVersionChecker: () => createLibraryVersionChecker,
|
|
@@ -425,6 +456,7 @@ __export(src_exports, {
|
|
|
425
456
|
createMenuShoppingComponent: () => createMenuShoppingComponent,
|
|
426
457
|
createModalFooter: () => createModalFooter,
|
|
427
458
|
createModalHeader: () => createModalHeader,
|
|
459
|
+
createMoneyVarianceColumn: () => createMoneyVarianceColumn,
|
|
428
460
|
createMyIOTheme: () => createMyIOTheme,
|
|
429
461
|
createNewTicketWizard: () => createNewTicketWizard,
|
|
430
462
|
createOnOffDeviceModal: () => createOnOffDeviceModal,
|
|
@@ -436,6 +468,7 @@ __export(src_exports, {
|
|
|
436
468
|
createPdfButton: () => createPdfButton,
|
|
437
469
|
createPresetupGateway: () => createPresetupGateway,
|
|
438
470
|
createRealTimeClock: () => createRealTimeClock,
|
|
471
|
+
createReportMoneyColumn: () => createReportMoneyColumn,
|
|
439
472
|
createScheduleCard: () => createScheduleCard,
|
|
440
473
|
createScheduleHoliday: () => createScheduleHoliday,
|
|
441
474
|
createScheduleIR: () => createScheduleIR,
|
|
@@ -445,6 +478,8 @@ __export(src_exports, {
|
|
|
445
478
|
createSidebarMenu: () => createSidebarMenu,
|
|
446
479
|
createSolenoidControl: () => createSolenoidControl,
|
|
447
480
|
createSwitchControl: () => createSwitchControl,
|
|
481
|
+
createTariffApiAdapter: () => createTariffApiAdapter,
|
|
482
|
+
createTariffApiClient: () => createTariffApiClient,
|
|
448
483
|
createTelemetryGridComponent: () => createTelemetryGridComponent,
|
|
449
484
|
createTelemetryGridShoppingComponent: () => createTelemetryGridShoppingComponent,
|
|
450
485
|
createTelemetryInfoShoppingComponent: () => createTelemetryInfoShoppingComponent,
|
|
@@ -455,6 +490,8 @@ __export(src_exports, {
|
|
|
455
490
|
createWidgetController: () => createWidgetController,
|
|
456
491
|
createXlsButton: () => createXlsButton,
|
|
457
492
|
csvEscapeAnnotation: () => csvEscape,
|
|
493
|
+
daysInMonthYear: () => daysInMonthYear,
|
|
494
|
+
decimalStringToCents: () => decimalStringToCents,
|
|
458
495
|
decodePayload: () => decodePayload,
|
|
459
496
|
decodePayloadBase64Xor: () => decodePayloadBase64Xor,
|
|
460
497
|
deleteFreshdeskTicket: () => deleteTicket,
|
|
@@ -465,6 +502,8 @@ __export(src_exports, {
|
|
|
465
502
|
detectSuperAdminHolding: () => detectSuperAdminHolding,
|
|
466
503
|
detectSuperAdminMyio: () => detectSuperAdminMyio,
|
|
467
504
|
determineInterval: () => determineInterval,
|
|
505
|
+
deviceCategoryLabel: () => deviceCategoryLabel,
|
|
506
|
+
deviceCategoryToPanelTerm: () => deviceCategoryToPanelTerm,
|
|
468
507
|
deviceIconLabels: () => deviceIconLabels,
|
|
469
508
|
deviceIcons: () => deviceIcons,
|
|
470
509
|
deviceStatusIcons: () => deviceStatusIcons,
|
|
@@ -473,6 +512,9 @@ __export(src_exports, {
|
|
|
473
512
|
downloadAnnotationsTextFile: () => downloadTextFile,
|
|
474
513
|
escapeAnnotationHtml: () => escapeHtml16,
|
|
475
514
|
evaluateDeviceStatus: () => evaluateDeviceStatus,
|
|
515
|
+
expandBandHours: () => expandBandHours,
|
|
516
|
+
expandBandToHourBucketsByYear: () => expandBandToHourBucketsByYear,
|
|
517
|
+
expandDayToHourBuckets: () => expandDayToHourBuckets,
|
|
476
518
|
exportAnnotationsCsv: () => exportAnnotationsCsv,
|
|
477
519
|
exportAnnotationsPdf: () => exportAnnotationsPdf,
|
|
478
520
|
exportGridCsv: () => exportGridCsv,
|
|
@@ -504,14 +546,17 @@ __export(src_exports, {
|
|
|
504
546
|
formatAllInSameUnit: () => formatAllInSameUnit,
|
|
505
547
|
formatAllInSameWaterUnit: () => formatAllInSameWaterUnit,
|
|
506
548
|
formatAnnotationRelativeTime: () => formatRelative,
|
|
549
|
+
formatBRLDelta: () => formatBRLDelta,
|
|
507
550
|
formatCoverageRefPtBR: () => formatCoverageRefPtBR,
|
|
508
551
|
formatDashboardPercentage: () => formatPercentage4,
|
|
509
552
|
formatDateForInput: () => formatDateForInput,
|
|
510
553
|
formatDateToYMD: () => formatDateToYMD,
|
|
511
554
|
formatDateWithTimezoneOffset: () => formatDateWithTimezoneOffset,
|
|
555
|
+
formatDeltaPct: () => formatDeltaPct,
|
|
512
556
|
formatDuration: () => formatDuration,
|
|
513
557
|
formatEnergy: () => formatEnergy,
|
|
514
558
|
formatHours: () => formatHours,
|
|
559
|
+
formatMoneyBRL: () => formatBRL,
|
|
515
560
|
formatNumberReadable: () => formatNumberReadable,
|
|
516
561
|
formatPower: () => formatPower,
|
|
517
562
|
formatRelativeTime: () => formatRelativeTime,
|
|
@@ -600,8 +645,10 @@ __export(src_exports, {
|
|
|
600
645
|
injectAmbienteGroupModalStyles: () => injectAmbienteGroupModalStyles,
|
|
601
646
|
injectAmbienteModalStyles: () => injectAmbienteModalStyles,
|
|
602
647
|
injectBASDashboardStyles: () => injectBASDashboardStyles,
|
|
648
|
+
injectCoverageStyles: () => injectCoverageStyles,
|
|
603
649
|
injectCustomerCardV1Styles: () => injectCustomerCardV1Styles,
|
|
604
650
|
injectCustomerCardV2Styles: () => injectCustomerCardV2Styles,
|
|
651
|
+
injectDeviceCategoryStyles: () => injectDeviceCategoryStyles,
|
|
605
652
|
injectDeviceGridV6Styles: () => injectStyles18,
|
|
606
653
|
injectDeviceOperationalCardGridStyles: () => injectDeviceOperationalCardGridStyles,
|
|
607
654
|
injectDeviceOperationalCardStyles: () => injectDeviceOperationalCardStyles,
|
|
@@ -641,6 +688,8 @@ __export(src_exports, {
|
|
|
641
688
|
isEquipmentDevice: () => isEquipmentDevice,
|
|
642
689
|
isHydrometerDevice: () => isHydrometerDevice,
|
|
643
690
|
isInRange: () => isInRange,
|
|
691
|
+
isLeapYear: () => isLeapYear,
|
|
692
|
+
isMoneyColumnConfident: () => isMoneyColumnConfident,
|
|
644
693
|
isOnOffDeviceProfile: () => isOnOffDeviceProfile,
|
|
645
694
|
isSolenoidDevice: () => isSolenoidDevice,
|
|
646
695
|
isStoreDevice: () => isStoreDevice,
|
|
@@ -661,9 +710,12 @@ __export(src_exports, {
|
|
|
661
710
|
metasGuideDeriveTotal: () => deriveTotal,
|
|
662
711
|
myioExportData: () => myioExportData,
|
|
663
712
|
nfdNormalizeAnnotationSearch: () => nfdNormalize,
|
|
713
|
+
normalizeBudgetBlock: () => normalizeBudgetBlock,
|
|
664
714
|
normalizeConnectionStatus: () => normalizeConnectionStatus,
|
|
665
715
|
normalizeDeviceOverrideId: () => normalizeDeviceOverrideId,
|
|
716
|
+
normalizeMoneyBlock: () => normalizeMoneyBlock,
|
|
666
717
|
normalizeOnOffStatus: () => normalizeOnOff,
|
|
718
|
+
normalizePriceString: () => normalizePriceString,
|
|
667
719
|
normalizeProfile: () => normalizeProfile,
|
|
668
720
|
normalizeRecipients: () => normalizeRecipients,
|
|
669
721
|
numbers: () => numbers_exports,
|
|
@@ -682,6 +734,7 @@ __export(src_exports, {
|
|
|
682
734
|
openDashboardPopupSettings: () => openDashboardPopupSettings,
|
|
683
735
|
openDashboardPopupWaterTank: () => openDashboardPopupWaterTank,
|
|
684
736
|
openDemandModal: () => openDemandModal,
|
|
737
|
+
openDeviceCategoryPanel: () => openDeviceCategoryPanel,
|
|
685
738
|
openDeviceProfileModal: () => openDeviceProfileModal,
|
|
686
739
|
openGCDRSyncModal: () => openGCDRSyncModal,
|
|
687
740
|
openGenericModal: () => openGenericModal,
|
|
@@ -705,6 +758,10 @@ __export(src_exports, {
|
|
|
705
758
|
openUpsellModal: () => openUpsellModal,
|
|
706
759
|
openUserManagementModal: () => openUserManagementModal,
|
|
707
760
|
openWelcomeModal: () => openWelcomeModal,
|
|
761
|
+
overlayWithholdsVerdict: () => overlayWithholdsVerdict,
|
|
762
|
+
panelCategoryToWire: () => panelCategoryToWire,
|
|
763
|
+
panelDomainToWire: () => panelDomainToWire,
|
|
764
|
+
panelTermToDeviceCategory: () => panelTermToDeviceCategory,
|
|
708
765
|
parseClassificationEntities: () => parseClassificationEntities,
|
|
709
766
|
parseInputDateToDate: () => parseInputDateToDate,
|
|
710
767
|
parseLogAnnotations: () => parseLogAnnotations,
|
|
@@ -725,17 +782,22 @@ __export(src_exports, {
|
|
|
725
782
|
removeSchedulingSharedStyles: () => removeSchedulingSharedStyles,
|
|
726
783
|
renderAlarmCard: () => renderAlarmCard,
|
|
727
784
|
renderAnnotationItemCard: () => renderAnnotationItemCard,
|
|
785
|
+
renderBudgetView: () => renderBudgetView,
|
|
728
786
|
renderCardAmbienteV6: () => renderCardAmbienteV6,
|
|
729
787
|
renderCardComponentHeadOffice: () => renderCardComponentHeadOffice,
|
|
730
788
|
renderCardComponentV5: () => renderCardComponent,
|
|
731
789
|
renderCardComponentV6: () => renderCardComponentV6,
|
|
732
790
|
renderCardComponentV6Alias: () => renderCardComponent2,
|
|
733
791
|
renderCardV5: () => renderCardComponentV5,
|
|
792
|
+
renderCoverageView: () => renderCoverageView,
|
|
734
793
|
renderDashboardDowntimeList: () => renderDowntimeList,
|
|
735
794
|
renderDeviceGridList: () => renderList,
|
|
736
795
|
renderDualLineChart: () => renderDualLineChart,
|
|
796
|
+
renderFinancialIndicators: () => renderFinancialIndicators,
|
|
797
|
+
renderGatedMoney: () => renderGatedMoney,
|
|
737
798
|
renderKPICards: () => renderKPICards,
|
|
738
799
|
renderLineChart: () => renderLineChart,
|
|
800
|
+
renderMoneyVariance: () => renderMoneyVariance,
|
|
739
801
|
renderOnOffTimelineChart: () => renderOnOffTimelineChart,
|
|
740
802
|
renderSeverityBarChart: () => renderSeverityBarChart,
|
|
741
803
|
renderStateDonutChart: () => renderStateDonutChart,
|
|
@@ -743,12 +805,17 @@ __export(src_exports, {
|
|
|
743
805
|
renderTrendChart: () => renderTrendChart,
|
|
744
806
|
reopenFreshdeskTicket: () => reopenTicket,
|
|
745
807
|
resolveActiveProfile: () => resolveActiveProfile,
|
|
808
|
+
resolveBudget: () => resolveBudget,
|
|
746
809
|
resolveCategory: () => resolveCategory,
|
|
747
810
|
resolveClassification: () => resolveClassification,
|
|
811
|
+
resolveGoalAmount: () => resolveGoalAmount,
|
|
748
812
|
resolveGroup: () => resolveGroup,
|
|
813
|
+
resolveMoneyRollout: () => resolveMoneyRollout,
|
|
814
|
+
resolveMoneyRowValues: () => resolveMoneyRowValues,
|
|
749
815
|
resolvePercentDecimals: () => resolvePercentDecimals,
|
|
750
816
|
resolveSubcategory: () => resolveSubcategory,
|
|
751
817
|
resolveWithFallback: () => resolveWithFallback,
|
|
818
|
+
routeMoneyRender: () => routeMoneyRender,
|
|
752
819
|
schedCreateDateInput: () => createDateInput,
|
|
753
820
|
schedCreateNumberInput: () => createNumberInput,
|
|
754
821
|
schedCreateSelect: () => createSelect,
|
|
@@ -760,10 +827,13 @@ __export(src_exports, {
|
|
|
760
827
|
setActiveProfile: () => setActiveProfile,
|
|
761
828
|
shouldFlashIcon: () => shouldFlashIcon,
|
|
762
829
|
shouldVirtualizeAnnotationList: () => shouldVirtualize,
|
|
830
|
+
signOf: () => signOf,
|
|
763
831
|
slugifyCustomerName: () => slugifyCustomerName,
|
|
764
832
|
sortAnnotationGroups: () => sortGroups,
|
|
765
833
|
sortDeviceGridDevices: () => sortDevices,
|
|
766
834
|
strings: () => strings_exports,
|
|
835
|
+
subtractDecimals: () => subtractDecimals,
|
|
836
|
+
sumMoneyDecimals: () => sumMoneyDecimals,
|
|
767
837
|
telemetryInfoFormatEnergy: () => formatEnergy2,
|
|
768
838
|
telemetryInfoFormatPercentage: () => formatPercentage3,
|
|
769
839
|
telemetryInfoFormatWater: () => formatWater2,
|
|
@@ -781,6 +851,8 @@ __export(src_exports, {
|
|
|
781
851
|
validateTree: () => validateTree,
|
|
782
852
|
version: () => version,
|
|
783
853
|
waterDeviceStatusIcons: () => waterDeviceStatusIcons,
|
|
854
|
+
wireCategoryToPanel: () => wireCategoryToPanel,
|
|
855
|
+
wireDomainToPanel: () => wireDomainToPanel,
|
|
784
856
|
writeFreshdeskSyncedAtToTB: () => writeFreshdeskSyncedAtToTB,
|
|
785
857
|
writeFreshdeskTicketsToTB: () => writeFreshdeskTicketsToTB
|
|
786
858
|
});
|
|
@@ -789,7 +861,7 @@ module.exports = __toCommonJS(src_exports);
|
|
|
789
861
|
// package.json
|
|
790
862
|
var package_default = {
|
|
791
863
|
name: "myio-js-library",
|
|
792
|
-
version: "0.1.
|
|
864
|
+
version: "0.1.530",
|
|
793
865
|
description: "A clean, standalone JS SDK for MYIO projects",
|
|
794
866
|
license: "MIT",
|
|
795
867
|
repository: "github:gh-myio/myio-js-library",
|
|
@@ -15376,9 +15448,6 @@ if (typeof globalThis !== "undefined" && typeof globalThis.window !== "undefined
|
|
|
15376
15448
|
} else {
|
|
15377
15449
|
MyIOSelectionStore = new MyIOSelectionStoreClass();
|
|
15378
15450
|
}
|
|
15379
|
-
if (typeof module !== "undefined" && module.exports) {
|
|
15380
|
-
module.exports = { MyIOSelectionStore, MyIOSelectionStoreClass };
|
|
15381
|
-
}
|
|
15382
15451
|
|
|
15383
15452
|
// src/components/DraggableCard.js
|
|
15384
15453
|
var MyIODraggableCard = class {
|
|
@@ -15704,9 +15773,6 @@ var MyIODraggableCard = class {
|
|
|
15704
15773
|
if (typeof globalThis !== "undefined" && typeof globalThis.window !== "undefined") {
|
|
15705
15774
|
globalThis.window.MyIODraggableCard = MyIODraggableCard;
|
|
15706
15775
|
}
|
|
15707
|
-
if (typeof module !== "undefined" && module.exports) {
|
|
15708
|
-
module.exports = { MyIODraggableCard };
|
|
15709
|
-
}
|
|
15710
15776
|
|
|
15711
15777
|
// src/utils/tooltips/DeviceComparisonTooltip.ts
|
|
15712
15778
|
var DEVICE_COMPARISON_TOOLTIP_CSS = `
|
|
@@ -24043,42 +24109,6 @@ var MyIOChartModalClass = class {
|
|
|
24043
24109
|
</div>
|
|
24044
24110
|
`;
|
|
24045
24111
|
}
|
|
24046
|
-
_generateSummaryHTML(totals) {
|
|
24047
|
-
const items = [];
|
|
24048
|
-
if (totals.energyKwh > 0) {
|
|
24049
|
-
items.push(`<div class="summary-item"
|
|
24050
|
-
style="background: rgba(255,255,255,0.08); padding: 10px; border-radius: 8px;">
|
|
24051
|
-
<span class="summary-label" style="display: block; font-size: 13px; color: rgba(255,255,255,0.7);">Energia Total:</span>
|
|
24052
|
-
<span class="summary-value" style="font-weight: bold; font-size: 14px;">${this._formatNumber(
|
|
24053
|
-
totals.energyKwh
|
|
24054
|
-
)} kWh</span>
|
|
24055
|
-
</div>`);
|
|
24056
|
-
}
|
|
24057
|
-
if (totals.waterM3 > 0) {
|
|
24058
|
-
items.push(`<div class="summary-item"
|
|
24059
|
-
style="background: rgba(255,255,255,0.08); padding: 10px; border-radius: 8px;">
|
|
24060
|
-
<span class="summary-label" style="display: block; font-size: 13px; color: rgba(255,255,255,0.7);">\xC1gua Total:</span>
|
|
24061
|
-
<span class="summary-value" style="font-weight: bold; font-size: 14px;">${this._formatNumber(
|
|
24062
|
-
totals.waterM3
|
|
24063
|
-
)} m\xB3</span>
|
|
24064
|
-
</div>`);
|
|
24065
|
-
}
|
|
24066
|
-
if (totals.tempC > 0) {
|
|
24067
|
-
items.push(`<div class="summary-item"
|
|
24068
|
-
style="background: rgba(255,255,255,0.08); padding: 10px; border-radius: 8px;">
|
|
24069
|
-
<span class="summary-label" style="display: block; font-size: 13px; color: rgba(255,255,255,0.7);">Temperatura M\xE9dia:</span>
|
|
24070
|
-
<span class="summary-value" style="font-weight: bold; font-size: 14px;">${this._formatNumber(
|
|
24071
|
-
totals.tempC / totals.count
|
|
24072
|
-
)} \xB0C</span>
|
|
24073
|
-
</div>`);
|
|
24074
|
-
}
|
|
24075
|
-
items.push(`<div class="summary-item"
|
|
24076
|
-
style="background: rgba(255,255,255,0.08); padding: 10px; border-radius: 8px;">
|
|
24077
|
-
<span class="summary-label" style="display: block; font-size: 13px; color: rgba(255,255,255,0.7);">Dispositivos:</span>
|
|
24078
|
-
<span class="summary-value" style="font-weight: bold; font-size: 14px;">${totals.count}</span>
|
|
24079
|
-
</div>`);
|
|
24080
|
-
return items.join("");
|
|
24081
|
-
}
|
|
24082
24112
|
_generateSummaryHTML(totals) {
|
|
24083
24113
|
const items = [];
|
|
24084
24114
|
if (totals.energyKwh > 0) {
|
|
@@ -24386,9 +24416,6 @@ var MyIOChartModal = new MyIOChartModalClass();
|
|
|
24386
24416
|
if (typeof globalThis !== "undefined" && typeof globalThis.window !== "undefined") {
|
|
24387
24417
|
globalThis.window.MyIOChartModal = MyIOChartModal;
|
|
24388
24418
|
}
|
|
24389
|
-
if (typeof module !== "undefined" && module.exports) {
|
|
24390
|
-
module.exports = { MyIOChartModal };
|
|
24391
|
-
}
|
|
24392
24419
|
|
|
24393
24420
|
// src/components/MyIOToast.js
|
|
24394
24421
|
var TOAST_MAX_MESSAGE_LENGTH = 100;
|
|
@@ -24608,9 +24635,6 @@ var MyIOToast = (function() {
|
|
|
24608
24635
|
error
|
|
24609
24636
|
};
|
|
24610
24637
|
})();
|
|
24611
|
-
if (typeof module !== "undefined" && module.exports) {
|
|
24612
|
-
module.exports = { MyIOToast };
|
|
24613
|
-
}
|
|
24614
24638
|
|
|
24615
24639
|
// src/components/loading-spinner/types.ts
|
|
24616
24640
|
var DEFAULT_LOADING_CONFIG = {
|
|
@@ -29266,8 +29290,8 @@ var EnergyDataFetcher = class {
|
|
|
29266
29290
|
// src/components/premium-modals/internal/engines/CsvExporter.ts
|
|
29267
29291
|
var toCsv = (rows, locale = "pt-BR", sep = ";") => {
|
|
29268
29292
|
const fmt2 = new Intl.NumberFormat(locale, { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
|
29269
|
-
const
|
|
29270
|
-
return rows.map((r) => r.map((c) => `"${
|
|
29293
|
+
const esc8 = (v) => (typeof v === "number" ? fmt2.format(v) : String(v)).replace(/"/g, '""');
|
|
29294
|
+
return rows.map((r) => r.map((c) => `"${esc8(c)}"`).join(sep)).join("\r\n");
|
|
29271
29295
|
};
|
|
29272
29296
|
|
|
29273
29297
|
// src/utils/telemetryUtils.ts
|
|
@@ -37056,6 +37080,823 @@ function attachFilterOrderingModal(props) {
|
|
|
37056
37080
|
};
|
|
37057
37081
|
}
|
|
37058
37082
|
|
|
37083
|
+
// src/components/financial-goals/moneyFormat.ts
|
|
37084
|
+
var DASH = "\u2014";
|
|
37085
|
+
function toDecimalParts(input) {
|
|
37086
|
+
const s = input.trim();
|
|
37087
|
+
if (!s) return null;
|
|
37088
|
+
const m = /^([+-]?)(\d+)(?:\.(\d+))?$/.exec(s);
|
|
37089
|
+
if (!m) return null;
|
|
37090
|
+
const negative = m[1] === "-";
|
|
37091
|
+
let intDigits = m[2].replace(/^0+(?=\d)/, "");
|
|
37092
|
+
const frac = m[3] || "";
|
|
37093
|
+
let cents = frac.slice(0, 2).padEnd(2, "0");
|
|
37094
|
+
const roundDigit = frac.charAt(2);
|
|
37095
|
+
if (roundDigit && roundDigit >= "5") {
|
|
37096
|
+
const bumped = String(Number(cents) + 1).padStart(2, "0");
|
|
37097
|
+
if (bumped.length > 2) {
|
|
37098
|
+
cents = "00";
|
|
37099
|
+
intDigits = incrementDigits(intDigits);
|
|
37100
|
+
} else {
|
|
37101
|
+
cents = bumped;
|
|
37102
|
+
}
|
|
37103
|
+
}
|
|
37104
|
+
return { negative, intDigits, frac2: cents };
|
|
37105
|
+
}
|
|
37106
|
+
function incrementDigits(digits) {
|
|
37107
|
+
const arr = digits.split("");
|
|
37108
|
+
let i = arr.length - 1;
|
|
37109
|
+
for (; i >= 0; i--) {
|
|
37110
|
+
if (arr[i] === "9") {
|
|
37111
|
+
arr[i] = "0";
|
|
37112
|
+
} else {
|
|
37113
|
+
arr[i] = String(Number(arr[i]) + 1);
|
|
37114
|
+
return arr.join("");
|
|
37115
|
+
}
|
|
37116
|
+
}
|
|
37117
|
+
return "1" + arr.join("");
|
|
37118
|
+
}
|
|
37119
|
+
function groupThousands(intDigits) {
|
|
37120
|
+
return intDigits.replace(/\B(?=(\d{3})+(?!\d))/g, ".");
|
|
37121
|
+
}
|
|
37122
|
+
function formatBRL(amount) {
|
|
37123
|
+
if (amount == null) return DASH;
|
|
37124
|
+
const parts = toDecimalParts(String(amount));
|
|
37125
|
+
if (!parts) return DASH;
|
|
37126
|
+
const grouped = groupThousands(parts.intDigits);
|
|
37127
|
+
const sign = parts.negative && !(parts.intDigits === "0" && parts.frac2 === "00") ? "-" : "";
|
|
37128
|
+
return `R$ ${sign}${grouped},${parts.frac2}`;
|
|
37129
|
+
}
|
|
37130
|
+
function signOf(value) {
|
|
37131
|
+
if (value == null || !Number.isFinite(value) || value === 0) return "";
|
|
37132
|
+
return value > 0 ? "+" : "\u2212";
|
|
37133
|
+
}
|
|
37134
|
+
function computeDeltaPct(current, baseline) {
|
|
37135
|
+
if (current == null || baseline == null) return null;
|
|
37136
|
+
const c = Number(String(current).trim());
|
|
37137
|
+
const b = Number(String(baseline).trim());
|
|
37138
|
+
if (!Number.isFinite(c) || !Number.isFinite(b) || b === 0) return null;
|
|
37139
|
+
return (c - b) / Math.abs(b) * 100;
|
|
37140
|
+
}
|
|
37141
|
+
function formatDeltaPct(pct, digits = 1) {
|
|
37142
|
+
if (pct == null || !Number.isFinite(pct)) return DASH;
|
|
37143
|
+
const abs = Math.abs(pct).toFixed(digits).replace(".", ",");
|
|
37144
|
+
const sign = pct > 0 ? "+" : pct < 0 ? "\u2212" : "";
|
|
37145
|
+
return `${sign}${abs}%`;
|
|
37146
|
+
}
|
|
37147
|
+
function formatBRLDelta(amount) {
|
|
37148
|
+
if (amount == null) return DASH;
|
|
37149
|
+
const parts = toDecimalParts(String(amount));
|
|
37150
|
+
if (!parts) return DASH;
|
|
37151
|
+
const isZero = parts.intDigits === "0" && parts.frac2 === "00";
|
|
37152
|
+
const sign = isZero ? "" : parts.negative ? "\u2212" : "+";
|
|
37153
|
+
const grouped = groupThousands(parts.intDigits);
|
|
37154
|
+
return `${sign}R$ ${grouped},${parts.frac2}`;
|
|
37155
|
+
}
|
|
37156
|
+
|
|
37157
|
+
// src/components/financial-goals/moneyTypes.ts
|
|
37158
|
+
var MONEY_REQUIRES_DEVICE_GRANULARITY = "MONEY_REQUIRES_DEVICE_GRANULARITY";
|
|
37159
|
+
function normalizeMoneyBlock(raw, rawBudget) {
|
|
37160
|
+
if (raw == null) {
|
|
37161
|
+
return { state: "unavailable", reason: MONEY_REQUIRES_DEVICE_GRANULARITY };
|
|
37162
|
+
}
|
|
37163
|
+
const hasCoverageFields = typeof raw.currency === "string" || typeof raw.coverageComplete === "boolean";
|
|
37164
|
+
if (!hasCoverageFields) {
|
|
37165
|
+
const reason = typeof raw.reason === "string" && raw.reason ? raw.reason : MONEY_REQUIRES_DEVICE_GRANULARITY;
|
|
37166
|
+
return { state: "unavailable", reason };
|
|
37167
|
+
}
|
|
37168
|
+
const overlay = {
|
|
37169
|
+
state: "available",
|
|
37170
|
+
currency: typeof raw.currency === "string" ? raw.currency : "BRL",
|
|
37171
|
+
coverageComplete: raw.coverageComplete === true,
|
|
37172
|
+
uncategorizedDevices: Array.isArray(raw.uncategorizedDevices) ? raw.uncategorizedDevices : []
|
|
37173
|
+
};
|
|
37174
|
+
if (typeof raw.pricedHours === "number") overlay.pricedHours = raw.pricedHours;
|
|
37175
|
+
if (typeof raw.totalHours === "number") overlay.totalHours = raw.totalHours;
|
|
37176
|
+
if (raw.tariffCoverageGaps) overlay.tariffCoverageGaps = raw.tariffCoverageGaps;
|
|
37177
|
+
const budget = normalizeBudgetBlock(rawBudget);
|
|
37178
|
+
if (budget) overlay.budget = budget;
|
|
37179
|
+
return overlay;
|
|
37180
|
+
}
|
|
37181
|
+
function normalizeBudgetBlock(rawBudget) {
|
|
37182
|
+
if (rawBudget == null || typeof rawBudget !== "object") return void 0;
|
|
37183
|
+
const projected = rawBudget.projected;
|
|
37184
|
+
if (!projected || typeof projected.amount !== "string") return void 0;
|
|
37185
|
+
const overlay = {
|
|
37186
|
+
projected: {
|
|
37187
|
+
amount: projected.amount,
|
|
37188
|
+
source: typeof projected.source === "string" ? projected.source : "OVERLAY",
|
|
37189
|
+
coverageComplete: projected.coverageComplete === true
|
|
37190
|
+
},
|
|
37191
|
+
verdict: {
|
|
37192
|
+
// Explicit `null` when withheld; only pass a boolean through unchanged.
|
|
37193
|
+
withinBudget: typeof rawBudget.withinBudget === "boolean" ? rawBudget.withinBudget : null,
|
|
37194
|
+
// Variance stays a decimal string, or null while incomplete.
|
|
37195
|
+
variance: typeof rawBudget.variance === "string" ? rawBudget.variance : null
|
|
37196
|
+
}
|
|
37197
|
+
};
|
|
37198
|
+
if (rawBudget.target && typeof rawBudget.target === "object" && typeof rawBudget.target.amount === "string") {
|
|
37199
|
+
overlay.target = {
|
|
37200
|
+
amount: rawBudget.target.amount,
|
|
37201
|
+
source: typeof rawBudget.target.source === "string" ? rawBudget.target.source : "NATIVE"
|
|
37202
|
+
};
|
|
37203
|
+
}
|
|
37204
|
+
return overlay;
|
|
37205
|
+
}
|
|
37206
|
+
|
|
37207
|
+
// src/components/financial-goals/coverageStyles.ts
|
|
37208
|
+
var COVERAGE_STYLE_ID = "myio-fin-coverage-styles";
|
|
37209
|
+
var COVERAGE_CSS = `
|
|
37210
|
+
.myio-cov {
|
|
37211
|
+
--_cov-bg: var(--myio-bg, #ffffff);
|
|
37212
|
+
--_cov-card: var(--myio-card, #f8fafc);
|
|
37213
|
+
--_cov-text: var(--myio-text, #1f2937);
|
|
37214
|
+
--_cov-muted: var(--myio-text-muted, #6b7280);
|
|
37215
|
+
--_cov-border: var(--myio-border, #e5e7eb);
|
|
37216
|
+
--_cov-brand: var(--myio-brand-700, #5b2c9d);
|
|
37217
|
+
--_cov-warn-bg: #fffbeb;
|
|
37218
|
+
--_cov-warn-border: #fde68a;
|
|
37219
|
+
--_cov-warn-text: #92400e;
|
|
37220
|
+
--_cov-ok-bg: #ecfdf5;
|
|
37221
|
+
--_cov-ok-border: #a7f3d0;
|
|
37222
|
+
--_cov-ok-text: #065f46;
|
|
37223
|
+
--_cov-info-bg: #eff6ff;
|
|
37224
|
+
--_cov-info-border: #bfdbfe;
|
|
37225
|
+
--_cov-info-text: #1e40af;
|
|
37226
|
+
font-family: 'Nunito', system-ui, -apple-system, sans-serif;
|
|
37227
|
+
color: var(--_cov-text);
|
|
37228
|
+
display: flex;
|
|
37229
|
+
flex-direction: column;
|
|
37230
|
+
gap: 10px;
|
|
37231
|
+
font-size: 13px;
|
|
37232
|
+
line-height: 1.45;
|
|
37233
|
+
}
|
|
37234
|
+
|
|
37235
|
+
/* ---- Unavailable panel (money view withheld \u2014 not an error, not R$ 0) ---- */
|
|
37236
|
+
.myio-cov__panel {
|
|
37237
|
+
border: 1px solid var(--_cov-border);
|
|
37238
|
+
border-left: 3px solid var(--_cov-brand);
|
|
37239
|
+
border-radius: 10px;
|
|
37240
|
+
background: var(--_cov-card);
|
|
37241
|
+
padding: 14px 16px;
|
|
37242
|
+
display: flex;
|
|
37243
|
+
flex-direction: column;
|
|
37244
|
+
gap: 6px;
|
|
37245
|
+
}
|
|
37246
|
+
.myio-cov__panel-title {
|
|
37247
|
+
font-weight: 800;
|
|
37248
|
+
font-size: 14px;
|
|
37249
|
+
display: flex;
|
|
37250
|
+
align-items: center;
|
|
37251
|
+
gap: 8px;
|
|
37252
|
+
}
|
|
37253
|
+
.myio-cov__panel-msg {
|
|
37254
|
+
color: var(--_cov-muted);
|
|
37255
|
+
margin: 0;
|
|
37256
|
+
}
|
|
37257
|
+
|
|
37258
|
+
/* ---- Complete: quiet, non-intrusive affordance ---- */
|
|
37259
|
+
.myio-cov__complete {
|
|
37260
|
+
display: inline-flex;
|
|
37261
|
+
align-items: center;
|
|
37262
|
+
gap: 6px;
|
|
37263
|
+
align-self: flex-start;
|
|
37264
|
+
padding: 3px 10px;
|
|
37265
|
+
border-radius: 999px;
|
|
37266
|
+
font-size: 12px;
|
|
37267
|
+
font-weight: 700;
|
|
37268
|
+
background: var(--_cov-ok-bg);
|
|
37269
|
+
color: var(--_cov-ok-text);
|
|
37270
|
+
border: 1px solid var(--_cov-ok-border);
|
|
37271
|
+
}
|
|
37272
|
+
|
|
37273
|
+
/* ---- Incomplete badge + covered fraction ---- */
|
|
37274
|
+
.myio-cov__badge {
|
|
37275
|
+
display: inline-flex;
|
|
37276
|
+
align-items: center;
|
|
37277
|
+
gap: 8px;
|
|
37278
|
+
align-self: flex-start;
|
|
37279
|
+
padding: 4px 12px;
|
|
37280
|
+
border-radius: 999px;
|
|
37281
|
+
font-size: 12px;
|
|
37282
|
+
font-weight: 800;
|
|
37283
|
+
background: var(--_cov-warn-bg);
|
|
37284
|
+
color: var(--_cov-warn-text);
|
|
37285
|
+
border: 1px solid var(--_cov-warn-border);
|
|
37286
|
+
}
|
|
37287
|
+
.myio-cov__badge-pct {
|
|
37288
|
+
font-variant-numeric: tabular-nums;
|
|
37289
|
+
font-weight: 800;
|
|
37290
|
+
}
|
|
37291
|
+
.myio-cov__hours {
|
|
37292
|
+
color: var(--_cov-muted);
|
|
37293
|
+
font-size: 12px;
|
|
37294
|
+
font-variant-numeric: tabular-nums;
|
|
37295
|
+
}
|
|
37296
|
+
.myio-cov__note {
|
|
37297
|
+
margin: 0;
|
|
37298
|
+
color: var(--_cov-muted);
|
|
37299
|
+
font-size: 12px;
|
|
37300
|
+
font-style: italic;
|
|
37301
|
+
}
|
|
37302
|
+
|
|
37303
|
+
/* ---- Uncategorized devices: each a deep-link click affordance to A5a ---- */
|
|
37304
|
+
.myio-cov__section-title {
|
|
37305
|
+
font-weight: 700;
|
|
37306
|
+
font-size: 12px;
|
|
37307
|
+
color: var(--_cov-text);
|
|
37308
|
+
margin: 4px 0 0;
|
|
37309
|
+
text-transform: uppercase;
|
|
37310
|
+
letter-spacing: 0.03em;
|
|
37311
|
+
}
|
|
37312
|
+
.myio-cov__devices {
|
|
37313
|
+
list-style: none;
|
|
37314
|
+
margin: 0;
|
|
37315
|
+
padding: 0;
|
|
37316
|
+
display: flex;
|
|
37317
|
+
flex-direction: column;
|
|
37318
|
+
gap: 6px;
|
|
37319
|
+
}
|
|
37320
|
+
.myio-cov__device {
|
|
37321
|
+
display: flex;
|
|
37322
|
+
align-items: center;
|
|
37323
|
+
justify-content: space-between;
|
|
37324
|
+
gap: 12px;
|
|
37325
|
+
width: 100%;
|
|
37326
|
+
text-align: left;
|
|
37327
|
+
padding: 9px 12px;
|
|
37328
|
+
border: 1px solid var(--_cov-border);
|
|
37329
|
+
border-radius: 8px;
|
|
37330
|
+
background: var(--_cov-bg);
|
|
37331
|
+
color: var(--_cov-text);
|
|
37332
|
+
font-family: inherit;
|
|
37333
|
+
font-size: 13px;
|
|
37334
|
+
cursor: pointer;
|
|
37335
|
+
transition: border-color 0.15s ease, background 0.15s ease;
|
|
37336
|
+
}
|
|
37337
|
+
.myio-cov__device:hover,
|
|
37338
|
+
.myio-cov__device:focus-visible {
|
|
37339
|
+
border-color: var(--_cov-brand);
|
|
37340
|
+
background: var(--_cov-card);
|
|
37341
|
+
outline: none;
|
|
37342
|
+
}
|
|
37343
|
+
.myio-cov__device-label {
|
|
37344
|
+
font-weight: 700;
|
|
37345
|
+
min-width: 0;
|
|
37346
|
+
overflow: hidden;
|
|
37347
|
+
text-overflow: ellipsis;
|
|
37348
|
+
white-space: nowrap;
|
|
37349
|
+
}
|
|
37350
|
+
.myio-cov__device-code {
|
|
37351
|
+
color: var(--_cov-muted);
|
|
37352
|
+
font-size: 12px;
|
|
37353
|
+
font-variant-numeric: tabular-nums;
|
|
37354
|
+
}
|
|
37355
|
+
.myio-cov__device-cta {
|
|
37356
|
+
color: var(--_cov-brand);
|
|
37357
|
+
font-weight: 800;
|
|
37358
|
+
font-size: 12px;
|
|
37359
|
+
white-space: nowrap;
|
|
37360
|
+
}
|
|
37361
|
+
|
|
37362
|
+
/* ---- Tariff coverage gaps summary ---- */
|
|
37363
|
+
.myio-cov__gaps {
|
|
37364
|
+
border: 1px solid var(--_cov-info-border);
|
|
37365
|
+
background: var(--_cov-info-bg);
|
|
37366
|
+
color: var(--_cov-info-text);
|
|
37367
|
+
border-radius: 8px;
|
|
37368
|
+
padding: 9px 12px;
|
|
37369
|
+
font-size: 12px;
|
|
37370
|
+
display: flex;
|
|
37371
|
+
flex-direction: column;
|
|
37372
|
+
gap: 2px;
|
|
37373
|
+
}
|
|
37374
|
+
.myio-cov__gaps-truncated {
|
|
37375
|
+
opacity: 0.85;
|
|
37376
|
+
font-style: italic;
|
|
37377
|
+
}
|
|
37378
|
+
|
|
37379
|
+
/* ---- Deep-link (unavailable state, generic manage-categories) ---- */
|
|
37380
|
+
.myio-cov__deeplink {
|
|
37381
|
+
align-self: flex-start;
|
|
37382
|
+
margin-top: 4px;
|
|
37383
|
+
padding: 7px 14px;
|
|
37384
|
+
border: 1px solid var(--_cov-brand);
|
|
37385
|
+
border-radius: 8px;
|
|
37386
|
+
background: transparent;
|
|
37387
|
+
color: var(--_cov-brand);
|
|
37388
|
+
font-family: inherit;
|
|
37389
|
+
font-size: 12px;
|
|
37390
|
+
font-weight: 800;
|
|
37391
|
+
cursor: pointer;
|
|
37392
|
+
transition: background 0.15s ease;
|
|
37393
|
+
}
|
|
37394
|
+
.myio-cov__deeplink:hover,
|
|
37395
|
+
.myio-cov__deeplink:focus-visible {
|
|
37396
|
+
background: var(--_cov-card);
|
|
37397
|
+
outline: none;
|
|
37398
|
+
}
|
|
37399
|
+
|
|
37400
|
+
@media (prefers-color-scheme: dark) {
|
|
37401
|
+
.myio-cov {
|
|
37402
|
+
--_cov-bg: var(--myio-bg, #0f172a);
|
|
37403
|
+
--_cov-card: var(--myio-card, #1e293b);
|
|
37404
|
+
--_cov-text: var(--myio-text, #e2e8f0);
|
|
37405
|
+
--_cov-muted: var(--myio-text-muted, #94a3b8);
|
|
37406
|
+
--_cov-border: var(--myio-border, #334155);
|
|
37407
|
+
--_cov-brand: var(--myio-brand-700, #a78bfa);
|
|
37408
|
+
--_cov-warn-bg: #3a2e0a;
|
|
37409
|
+
--_cov-warn-border: #7c5e12;
|
|
37410
|
+
--_cov-warn-text: #fcd34d;
|
|
37411
|
+
--_cov-ok-bg: #08312a;
|
|
37412
|
+
--_cov-ok-border: #14654f;
|
|
37413
|
+
--_cov-ok-text: #6ee7b7;
|
|
37414
|
+
--_cov-info-bg: #0e2748;
|
|
37415
|
+
--_cov-info-border: #1e4a86;
|
|
37416
|
+
--_cov-info-text: #93c5fd;
|
|
37417
|
+
}
|
|
37418
|
+
}
|
|
37419
|
+
/* Host theme toggle wins in both directions. */
|
|
37420
|
+
:root[data-theme="dark"] .myio-cov {
|
|
37421
|
+
--_cov-bg: var(--myio-bg, #0f172a);
|
|
37422
|
+
--_cov-card: var(--myio-card, #1e293b);
|
|
37423
|
+
--_cov-text: var(--myio-text, #e2e8f0);
|
|
37424
|
+
--_cov-muted: var(--myio-text-muted, #94a3b8);
|
|
37425
|
+
--_cov-border: var(--myio-border, #334155);
|
|
37426
|
+
--_cov-brand: var(--myio-brand-700, #a78bfa);
|
|
37427
|
+
--_cov-warn-bg: #3a2e0a; --_cov-warn-border: #7c5e12; --_cov-warn-text: #fcd34d;
|
|
37428
|
+
--_cov-ok-bg: #08312a; --_cov-ok-border: #14654f; --_cov-ok-text: #6ee7b7;
|
|
37429
|
+
--_cov-info-bg: #0e2748; --_cov-info-border: #1e4a86; --_cov-info-text: #93c5fd;
|
|
37430
|
+
}
|
|
37431
|
+
:root[data-theme="light"] .myio-cov {
|
|
37432
|
+
--_cov-bg: var(--myio-bg, #ffffff);
|
|
37433
|
+
--_cov-card: var(--myio-card, #f8fafc);
|
|
37434
|
+
--_cov-text: var(--myio-text, #1f2937);
|
|
37435
|
+
--_cov-muted: var(--myio-text-muted, #6b7280);
|
|
37436
|
+
--_cov-border: var(--myio-border, #e5e7eb);
|
|
37437
|
+
--_cov-brand: var(--myio-brand-700, #5b2c9d);
|
|
37438
|
+
--_cov-warn-bg: #fffbeb; --_cov-warn-border: #fde68a; --_cov-warn-text: #92400e;
|
|
37439
|
+
--_cov-ok-bg: #ecfdf5; --_cov-ok-border: #a7f3d0; --_cov-ok-text: #065f46;
|
|
37440
|
+
--_cov-info-bg: #eff6ff; --_cov-info-border: #bfdbfe; --_cov-info-text: #1e40af;
|
|
37441
|
+
}
|
|
37442
|
+
`;
|
|
37443
|
+
function injectCoverageStyles(doc) {
|
|
37444
|
+
if (!doc || !doc.head) return;
|
|
37445
|
+
if (doc.getElementById(COVERAGE_STYLE_ID)) return;
|
|
37446
|
+
const style = doc.createElement("style");
|
|
37447
|
+
style.id = COVERAGE_STYLE_ID;
|
|
37448
|
+
style.textContent = COVERAGE_CSS;
|
|
37449
|
+
doc.head.appendChild(style);
|
|
37450
|
+
}
|
|
37451
|
+
|
|
37452
|
+
// src/components/financial-goals/coverageView.ts
|
|
37453
|
+
function groupInt(n) {
|
|
37454
|
+
return String(Math.trunc(Math.abs(n))).replace(/\B(?=(\d{3})+(?!\d))/g, ".");
|
|
37455
|
+
}
|
|
37456
|
+
function coveragePercentLabel(pricedHours, totalHours) {
|
|
37457
|
+
if (typeof pricedHours !== "number" || typeof totalHours !== "number" || !Number.isFinite(pricedHours) || !Number.isFinite(totalHours) || totalHours <= 0) {
|
|
37458
|
+
return DASH;
|
|
37459
|
+
}
|
|
37460
|
+
const pct = pricedHours / totalHours * 100;
|
|
37461
|
+
if (!Number.isFinite(pct)) return DASH;
|
|
37462
|
+
const rounded = Math.round(pct * 10) / 10;
|
|
37463
|
+
const txt = Number.isInteger(rounded) ? String(rounded) : rounded.toFixed(1).replace(".", ",");
|
|
37464
|
+
return `${txt}%`;
|
|
37465
|
+
}
|
|
37466
|
+
function esc(s) {
|
|
37467
|
+
return String(s ?? "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
37468
|
+
}
|
|
37469
|
+
function deviceDisplayName(d) {
|
|
37470
|
+
return esc(d.label || d.code || d.deviceId || "Dispositivo");
|
|
37471
|
+
}
|
|
37472
|
+
function unavailableHTML(reason, offerDeepLink) {
|
|
37473
|
+
const isGranularity2 = reason === MONEY_REQUIRES_DEVICE_GRANULARITY;
|
|
37474
|
+
const msg = isGranularity2 ? "A meta precisa ser por dispositivo (device-granular) com categoria de tarifa." : "Vis\xE3o em R$ n\xE3o dispon\xEDvel para esta meta.";
|
|
37475
|
+
const deepLink = offerDeepLink ? `<button type="button" class="myio-cov__deeplink" data-cov-manage="1">Gerenciar categorias de tarifa</button>` : "";
|
|
37476
|
+
return `<div class="myio-cov__panel" role="status"><div class="myio-cov__panel-title"><span aria-hidden="true">\u{1F4B8}</span>Vis\xE3o em R$ indispon\xEDvel</div><p class="myio-cov__panel-msg">${msg}</p>` + deepLink + `</div>`;
|
|
37477
|
+
}
|
|
37478
|
+
function completeHTML() {
|
|
37479
|
+
return `<span class="myio-cov__complete" role="status"><span aria-hidden="true">\u2713</span>Cobertura completa</span>`;
|
|
37480
|
+
}
|
|
37481
|
+
function devicesHTML(devices) {
|
|
37482
|
+
if (!devices.length) return "";
|
|
37483
|
+
const items = devices.map((d) => {
|
|
37484
|
+
const name = deviceDisplayName(d);
|
|
37485
|
+
const code = d.code ? `<span class="myio-cov__device-code">${esc(d.code)}</span>` : "";
|
|
37486
|
+
return `<li><button type="button" class="myio-cov__device" data-cov-device="${esc(d.deviceId)}"><span class="myio-cov__device-label">${name}</span>` + code + `<span class="myio-cov__device-cta">Categorizar \u2192</span></button></li>`;
|
|
37487
|
+
}).join("");
|
|
37488
|
+
return `<div class="myio-cov__section-title">Dispositivos sem categoria de tarifa</div><ul class="myio-cov__devices">${items}</ul>`;
|
|
37489
|
+
}
|
|
37490
|
+
function gapsHTML(gaps) {
|
|
37491
|
+
if (!gaps) return "";
|
|
37492
|
+
const hours = typeof gaps.missingHours === "number" && Number.isFinite(gaps.missingHours) ? groupInt(gaps.missingHours) : DASH;
|
|
37493
|
+
const truncated = gaps.truncated ? `<span class="myio-cov__gaps-truncated">Lista de horas resumida (truncada).</span>` : "";
|
|
37494
|
+
return `<div class="myio-cov__gaps" role="status"><span><strong>${hours}</strong> horas-dispositivo sem tarifa.</span>` + truncated + `</div>`;
|
|
37495
|
+
}
|
|
37496
|
+
function incompleteHTML(overlay) {
|
|
37497
|
+
const pctLabel = coveragePercentLabel(overlay.pricedHours, overlay.totalHours);
|
|
37498
|
+
const hoursDetail = typeof overlay.pricedHours === "number" && typeof overlay.totalHours === "number" ? `<span class="myio-cov__hours">${groupInt(overlay.pricedHours)} / ${groupInt(
|
|
37499
|
+
overlay.totalHours
|
|
37500
|
+
)} horas-dispositivo cobertas</span>` : "";
|
|
37501
|
+
return `<span class="myio-cov__badge" role="status"><span aria-hidden="true">\u26A0\uFE0F</span>Cobertura incompleta<span class="myio-cov__badge-pct">${pctLabel}</span></span>` + hoursDetail + `<p class="myio-cov__note">A Estimativa em R$ \xE9 uma soma parcial coberta, n\xE3o um total.</p>` + devicesHTML(overlay.uncategorizedDevices) + gapsHTML(overlay.tariffCoverageGaps);
|
|
37502
|
+
}
|
|
37503
|
+
function buildCoverageHTML(overlay, offerDeepLink = false) {
|
|
37504
|
+
if (!overlay || overlay.state == null) {
|
|
37505
|
+
return unavailableHTML(MONEY_REQUIRES_DEVICE_GRANULARITY, offerDeepLink);
|
|
37506
|
+
}
|
|
37507
|
+
if (overlay.state === "unavailable") {
|
|
37508
|
+
return unavailableHTML(overlay.reason, offerDeepLink);
|
|
37509
|
+
}
|
|
37510
|
+
if (overlay.coverageComplete) {
|
|
37511
|
+
return completeHTML();
|
|
37512
|
+
}
|
|
37513
|
+
return incompleteHTML(overlay);
|
|
37514
|
+
}
|
|
37515
|
+
function renderCoverageView(overlay, options = {}) {
|
|
37516
|
+
const doc = options.document || (typeof document !== "undefined" ? document : void 0);
|
|
37517
|
+
if (!doc) {
|
|
37518
|
+
throw new Error("renderCoverageView requires a document (pass options.document in non-DOM envs).");
|
|
37519
|
+
}
|
|
37520
|
+
injectCoverageStyles(doc);
|
|
37521
|
+
const offerDeepLink = (!overlay || overlay.state === "unavailable") && typeof options.onManageCategories === "function";
|
|
37522
|
+
const root = doc.createElement("div");
|
|
37523
|
+
root.className = "myio-cov";
|
|
37524
|
+
root.setAttribute(
|
|
37525
|
+
"data-cov-state",
|
|
37526
|
+
!overlay || overlay.state === "unavailable" ? "unavailable" : overlay.coverageComplete ? "available-complete" : "available-incomplete"
|
|
37527
|
+
);
|
|
37528
|
+
root.innerHTML = buildCoverageHTML(overlay, offerDeepLink);
|
|
37529
|
+
if (typeof options.onCategorizeDevice === "function") {
|
|
37530
|
+
const cb = options.onCategorizeDevice;
|
|
37531
|
+
root.querySelectorAll("[data-cov-device]").forEach((btn) => {
|
|
37532
|
+
btn.addEventListener("click", (ev) => {
|
|
37533
|
+
ev.preventDefault();
|
|
37534
|
+
ev.stopPropagation();
|
|
37535
|
+
const id = btn.getAttribute("data-cov-device") || "";
|
|
37536
|
+
cb(id);
|
|
37537
|
+
});
|
|
37538
|
+
});
|
|
37539
|
+
}
|
|
37540
|
+
if (offerDeepLink && typeof options.onManageCategories === "function") {
|
|
37541
|
+
const mcb = options.onManageCategories;
|
|
37542
|
+
const manageBtn = root.querySelector("[data-cov-manage]");
|
|
37543
|
+
if (manageBtn) {
|
|
37544
|
+
manageBtn.addEventListener("click", (ev) => {
|
|
37545
|
+
ev.preventDefault();
|
|
37546
|
+
ev.stopPropagation();
|
|
37547
|
+
mcb();
|
|
37548
|
+
});
|
|
37549
|
+
}
|
|
37550
|
+
}
|
|
37551
|
+
return root;
|
|
37552
|
+
}
|
|
37553
|
+
|
|
37554
|
+
// src/components/financial-goals/reportMoneyColumn.ts
|
|
37555
|
+
var REPORT_MONEY_HEADER = "Custo projetado (R$)";
|
|
37556
|
+
function isMoneyColumnConfident(overlay) {
|
|
37557
|
+
return !!overlay && overlay.state === "available" && overlay.coverageComplete === true;
|
|
37558
|
+
}
|
|
37559
|
+
function hasAmount(s) {
|
|
37560
|
+
return typeof s === "string" && s.trim() !== "";
|
|
37561
|
+
}
|
|
37562
|
+
function decimalStringToCents(s) {
|
|
37563
|
+
if (!hasAmount(s)) return null;
|
|
37564
|
+
const m = /^([+-]?)(\d+)(?:\.(\d+))?$/.exec(s.trim());
|
|
37565
|
+
if (!m) return null;
|
|
37566
|
+
const negative = m[1] === "-";
|
|
37567
|
+
const whole = BigInt(m[2]);
|
|
37568
|
+
const frac = m[3] || "";
|
|
37569
|
+
let cents = BigInt(frac.slice(0, 2).padEnd(2, "0"));
|
|
37570
|
+
if (frac.charAt(2) >= "5") cents += 1n;
|
|
37571
|
+
const total = whole * 100n + cents;
|
|
37572
|
+
return negative ? -total : total;
|
|
37573
|
+
}
|
|
37574
|
+
function centsToDecimalString(cents) {
|
|
37575
|
+
const negative = cents < 0n;
|
|
37576
|
+
const abs = negative ? -cents : cents;
|
|
37577
|
+
const whole = abs / 100n;
|
|
37578
|
+
const rem = abs % 100n;
|
|
37579
|
+
return `${negative ? "-" : ""}${whole.toString()}.${rem.toString().padStart(2, "0")}`;
|
|
37580
|
+
}
|
|
37581
|
+
function sumMoneyDecimals(values) {
|
|
37582
|
+
if (!Array.isArray(values) || values.length === 0) return null;
|
|
37583
|
+
let acc = 0n;
|
|
37584
|
+
for (const v of values) {
|
|
37585
|
+
const c = decimalStringToCents(v);
|
|
37586
|
+
if (c == null) return null;
|
|
37587
|
+
acc += c;
|
|
37588
|
+
}
|
|
37589
|
+
return centsToDecimalString(acc);
|
|
37590
|
+
}
|
|
37591
|
+
function cellInner(value) {
|
|
37592
|
+
return `<span data-money-cell="1">${formatBRL(value ?? null)}</span>`;
|
|
37593
|
+
}
|
|
37594
|
+
function varianceNoteHTML(variance) {
|
|
37595
|
+
if (!hasAmount(variance)) return "";
|
|
37596
|
+
return `<span data-money-variance="1" style="margin-left:6px;font:600 10px Nunito,sans-serif;color:var(--myio-text-muted,#94a3b8);">vs Meta ${formatBRLDelta(variance)}</span>`;
|
|
37597
|
+
}
|
|
37598
|
+
var DISABLED_COLUMN = {
|
|
37599
|
+
enabled: false,
|
|
37600
|
+
headerCellHTML: () => "",
|
|
37601
|
+
bodyCellHTML: () => "",
|
|
37602
|
+
cellValueHTML: () => "",
|
|
37603
|
+
resolveTotal: () => null,
|
|
37604
|
+
totalHTML: () => ""
|
|
37605
|
+
};
|
|
37606
|
+
function createReportMoneyColumn(config2) {
|
|
37607
|
+
if (!config2 || typeof config2.overlay?.state !== "string") {
|
|
37608
|
+
return DISABLED_COLUMN;
|
|
37609
|
+
}
|
|
37610
|
+
const overlay = config2.overlay;
|
|
37611
|
+
const perDevice = config2.perDevice || {};
|
|
37612
|
+
const label = config2.headerLabel || REPORT_MONEY_HEADER;
|
|
37613
|
+
const valueFor = (deviceId) => hasAmount(deviceId) ? perDevice[deviceId] : null;
|
|
37614
|
+
const resolveTotal = (rowValues) => {
|
|
37615
|
+
if (!isMoneyColumnConfident(overlay)) {
|
|
37616
|
+
return { kind: "coverage", overlay };
|
|
37617
|
+
}
|
|
37618
|
+
if (hasAmount(config2.total)) {
|
|
37619
|
+
return {
|
|
37620
|
+
kind: "amount",
|
|
37621
|
+
amount: config2.total,
|
|
37622
|
+
formatted: formatBRL(config2.total),
|
|
37623
|
+
source: "backend"
|
|
37624
|
+
};
|
|
37625
|
+
}
|
|
37626
|
+
const summed = sumMoneyDecimals(rowValues || []);
|
|
37627
|
+
if (summed == null) {
|
|
37628
|
+
return { kind: "coverage", overlay };
|
|
37629
|
+
}
|
|
37630
|
+
return {
|
|
37631
|
+
kind: "amount",
|
|
37632
|
+
amount: summed,
|
|
37633
|
+
formatted: formatBRL(summed),
|
|
37634
|
+
source: "row-sum"
|
|
37635
|
+
};
|
|
37636
|
+
};
|
|
37637
|
+
return {
|
|
37638
|
+
enabled: true,
|
|
37639
|
+
headerCellHTML: () => `<th data-money-col="1" style="text-align:right;white-space:nowrap;">${label}</th>`,
|
|
37640
|
+
bodyCellHTML: (deviceId) => `<td data-money-col="1" data-label="${label}" style="text-align:right;font-weight:bold;">${cellInner(
|
|
37641
|
+
valueFor(deviceId)
|
|
37642
|
+
)}</td>`,
|
|
37643
|
+
cellValueHTML: (deviceId) => cellInner(valueFor(deviceId)),
|
|
37644
|
+
resolveTotal,
|
|
37645
|
+
totalHTML: (rowValues) => {
|
|
37646
|
+
const total = resolveTotal(rowValues);
|
|
37647
|
+
if (total.kind === "coverage") {
|
|
37648
|
+
return `<span data-money-total="coverage">${buildCoverageHTML(total.overlay, false)}</span>`;
|
|
37649
|
+
}
|
|
37650
|
+
return `<span data-money-total="amount" data-money-source="${total.source}">${total.formatted}</span>` + varianceNoteHTML(config2.variance);
|
|
37651
|
+
}
|
|
37652
|
+
};
|
|
37653
|
+
}
|
|
37654
|
+
|
|
37655
|
+
// src/components/financial-goals/financialIndicators.ts
|
|
37656
|
+
var DEFAULT_CHIP = {
|
|
37657
|
+
overBg: "#fee2e2",
|
|
37658
|
+
overText: "#b91c1c",
|
|
37659
|
+
underBg: "#dcfce7",
|
|
37660
|
+
underText: "#15803d",
|
|
37661
|
+
neutralBg: "#f1f5f9",
|
|
37662
|
+
neutralText: "#64748b"
|
|
37663
|
+
};
|
|
37664
|
+
var DEFAULT_VALUE_COLORS = {
|
|
37665
|
+
realized: "#2563eb",
|
|
37666
|
+
orcado: "#f59e0b",
|
|
37667
|
+
meta: "#7c3aed",
|
|
37668
|
+
prevYear: "#94a3b8"
|
|
37669
|
+
};
|
|
37670
|
+
var APPROX_PCT = 1;
|
|
37671
|
+
function hasAmount2(s) {
|
|
37672
|
+
return typeof s === "string" && s.trim() !== "";
|
|
37673
|
+
}
|
|
37674
|
+
function resolveMoneyRowValues(overlay, money) {
|
|
37675
|
+
const budget = overlay && overlay.state === "available" ? overlay.budget : void 0;
|
|
37676
|
+
const orcado = hasAmount2(money?.orcado) ? money.orcado : hasAmount2(budget?.projected?.amount) ? budget.projected.amount : null;
|
|
37677
|
+
const meta = hasAmount2(money?.meta) ? money.meta : hasAmount2(budget?.target?.amount) ? budget.target.amount : null;
|
|
37678
|
+
return {
|
|
37679
|
+
realized: hasAmount2(money?.realized) ? money.realized : null,
|
|
37680
|
+
orcado,
|
|
37681
|
+
meta,
|
|
37682
|
+
prevYear: hasAmount2(money?.prevYear) ? money.prevYear : null
|
|
37683
|
+
};
|
|
37684
|
+
}
|
|
37685
|
+
var CHIP_BASE = "border-radius:999px;padding:2px 10px;font:700 11px Nunito,sans-serif;white-space:nowrap;";
|
|
37686
|
+
function chipHTML(realized, reference, colors2) {
|
|
37687
|
+
const pct = computeDeltaPct(realized, reference);
|
|
37688
|
+
if (pct == null) {
|
|
37689
|
+
return `<span data-fin-chip="none" style="background:${colors2.neutralBg};color:${colors2.neutralText};${CHIP_BASE}">${DASH}</span>`;
|
|
37690
|
+
}
|
|
37691
|
+
const deltaAmount = hasAmount2(realized) && hasAmount2(reference) ? formatBRLDelta(subtractDecimals(realized, reference)) : DASH;
|
|
37692
|
+
const pctTxt = formatDeltaPct(pct);
|
|
37693
|
+
if (Math.abs(pct) < APPROX_PCT) {
|
|
37694
|
+
return `<span data-fin-chip="approx" title="${deltaAmount}" style="background:${colors2.neutralBg};color:${colors2.neutralText};${CHIP_BASE}">≈ ${pctTxt}</span>`;
|
|
37695
|
+
}
|
|
37696
|
+
if (pct > 0) {
|
|
37697
|
+
return `<span data-fin-chip="over" title="${deltaAmount}" style="background:${colors2.overBg};color:${colors2.overText};${CHIP_BASE}">↑ ${pctTxt}</span>`;
|
|
37698
|
+
}
|
|
37699
|
+
return `<span data-fin-chip="under" title="${deltaAmount}" style="background:${colors2.underBg};color:${colors2.underText};${CHIP_BASE}">↓ ${pctTxt}</span>`;
|
|
37700
|
+
}
|
|
37701
|
+
function parseCents(s) {
|
|
37702
|
+
if (!hasAmount2(s)) return null;
|
|
37703
|
+
const m = /^([+-]?)(\d+)(?:\.(\d+))?$/.exec(s.trim());
|
|
37704
|
+
if (!m) return null;
|
|
37705
|
+
const sign = m[1] === "-" ? -1 : 1;
|
|
37706
|
+
const whole = Number(m[2]);
|
|
37707
|
+
const frac = (m[3] || "").padEnd(3, "0");
|
|
37708
|
+
let cents = Number(frac.slice(0, 2));
|
|
37709
|
+
if (frac.charAt(2) >= "5") cents += 1;
|
|
37710
|
+
const total = whole * 100 + cents;
|
|
37711
|
+
return Number.isFinite(total) ? sign * total : null;
|
|
37712
|
+
}
|
|
37713
|
+
function subtractDecimals(a, b) {
|
|
37714
|
+
const pa = parseCents(a);
|
|
37715
|
+
const pb = parseCents(b);
|
|
37716
|
+
if (pa == null || pb == null) return null;
|
|
37717
|
+
const diff = pa - pb;
|
|
37718
|
+
const neg = diff < 0;
|
|
37719
|
+
const abs = Math.abs(diff);
|
|
37720
|
+
const intPart = Math.trunc(abs / 100);
|
|
37721
|
+
const cents = String(abs % 100).padStart(2, "0");
|
|
37722
|
+
return `${neg ? "-" : ""}${intPart}.${cents}`;
|
|
37723
|
+
}
|
|
37724
|
+
function figureHTML(label, amount, color) {
|
|
37725
|
+
return `<span style="display:inline-flex;align-items:center;gap:4px;white-space:nowrap;"><span style="color:${color};font-weight:700;">${label}</span><b style="color:var(--gc-text2, #334155);font-weight:700;">${formatBRL(amount)}</b></span>`;
|
|
37726
|
+
}
|
|
37727
|
+
function buildFinancialRowHTML(values, chipBaseline, chipColors, valueColors) {
|
|
37728
|
+
const reference = chipBaseline === "prevYear" ? values.prevYear : hasAmount2(values.meta) ? values.meta : values.prevYear;
|
|
37729
|
+
const figures = [
|
|
37730
|
+
figureHTML("Realizado", values.realized, valueColors.realized),
|
|
37731
|
+
figureHTML("Or\xE7ado", values.orcado, valueColors.orcado),
|
|
37732
|
+
figureHTML("Meta", values.meta, valueColors.meta)
|
|
37733
|
+
].join("");
|
|
37734
|
+
return `<div class="myio-fin__row" data-fin-row="1" style="display:flex;align-items:center;justify-content:space-between;gap:8px;"><div style="font:600 11px Nunito,sans-serif;color:var(--gc-muted, #64748b);display:flex;align-items:center;gap:8px;flex-wrap:wrap;min-width:0;"><span aria-hidden="true">\u{1F4B0}</span>` + figures + `</div>` + chipHTML(values.realized, reference, chipColors) + `</div><div class="myio-fin__note" style="font:600 10px Nunito,sans-serif;color:var(--gc-muted, #94a3b8);margin-top:2px;">Estimativa em R$</div>`;
|
|
37735
|
+
}
|
|
37736
|
+
function renderFinancialIndicators(options) {
|
|
37737
|
+
const overlay = options?.overlay;
|
|
37738
|
+
if (!overlay || typeof overlay.state !== "string") {
|
|
37739
|
+
return null;
|
|
37740
|
+
}
|
|
37741
|
+
const doc = options.document || (typeof document !== "undefined" ? document : void 0);
|
|
37742
|
+
if (!doc) {
|
|
37743
|
+
throw new Error(
|
|
37744
|
+
"renderFinancialIndicators requires a document (pass options.document in non-DOM envs)."
|
|
37745
|
+
);
|
|
37746
|
+
}
|
|
37747
|
+
const coverageOpts = {
|
|
37748
|
+
onCategorizeDevice: options.onCategorizeDevice,
|
|
37749
|
+
onManageCategories: options.onManageCategories,
|
|
37750
|
+
document: doc
|
|
37751
|
+
};
|
|
37752
|
+
if (overlay.state === "unavailable" || overlay.coverageComplete !== true) {
|
|
37753
|
+
return renderCoverageView(overlay, coverageOpts);
|
|
37754
|
+
}
|
|
37755
|
+
const values = resolveMoneyRowValues(overlay, options.money);
|
|
37756
|
+
const chipColors = { ...DEFAULT_CHIP, ...options.chipColors };
|
|
37757
|
+
const valueColors = {
|
|
37758
|
+
...DEFAULT_VALUE_COLORS,
|
|
37759
|
+
...options.valueColors
|
|
37760
|
+
};
|
|
37761
|
+
const chipBaseline = options.chipBaseline === "prevYear" ? "prevYear" : "meta";
|
|
37762
|
+
const root = doc.createElement("div");
|
|
37763
|
+
root.className = "myio-fin";
|
|
37764
|
+
root.setAttribute("data-fin-state", "available-money");
|
|
37765
|
+
root.innerHTML = buildFinancialRowHTML(values, chipBaseline, chipColors, valueColors);
|
|
37766
|
+
return root;
|
|
37767
|
+
}
|
|
37768
|
+
|
|
37769
|
+
// src/components/financial-goals/moneyVariance.ts
|
|
37770
|
+
var VARIANCE_LABEL_ABOVE = "Acima da meta (R$)";
|
|
37771
|
+
var VARIANCE_LABEL_BELOW = "Abaixo da meta (R$)";
|
|
37772
|
+
var VARIANCE_LABEL_ONTARGET = "Na meta (R$)";
|
|
37773
|
+
var VARIANCE_LABEL_WITHHELD = "Varia\xE7\xE3o indispon\xEDvel";
|
|
37774
|
+
var MONEY_VARIANCE_HEADER = "Varia\xE7\xE3o vs meta (R$)";
|
|
37775
|
+
var WITHHELD_RESULT = Object.freeze({
|
|
37776
|
+
verdict: "withheld",
|
|
37777
|
+
variance: null,
|
|
37778
|
+
pct: null
|
|
37779
|
+
});
|
|
37780
|
+
function hasAmount3(s) {
|
|
37781
|
+
return typeof s === "string" && s.trim() !== "";
|
|
37782
|
+
}
|
|
37783
|
+
function overlayWithholdsVerdict(overlay) {
|
|
37784
|
+
if (!overlay || typeof overlay.state !== "string") return false;
|
|
37785
|
+
if (overlay.state === "unavailable") return true;
|
|
37786
|
+
if (overlay.coverageComplete !== true) return true;
|
|
37787
|
+
const verdict = overlay.budget?.verdict;
|
|
37788
|
+
if (verdict && verdict.withinBudget !== true && verdict.withinBudget !== false) {
|
|
37789
|
+
return true;
|
|
37790
|
+
}
|
|
37791
|
+
return false;
|
|
37792
|
+
}
|
|
37793
|
+
function resolveGoalAmount(input) {
|
|
37794
|
+
if (hasAmount3(input.currencyBudget)) return input.currencyBudget;
|
|
37795
|
+
const overlay = input.overlay;
|
|
37796
|
+
if (overlay && overlay.state === "available" && hasAmount3(overlay.budget?.target?.amount)) {
|
|
37797
|
+
return overlay.budget.target.amount;
|
|
37798
|
+
}
|
|
37799
|
+
return null;
|
|
37800
|
+
}
|
|
37801
|
+
function computeMoneyVariance(input) {
|
|
37802
|
+
if (!input || input.withheld === true) return WITHHELD_RESULT;
|
|
37803
|
+
if (overlayWithholdsVerdict(input.overlay)) return WITHHELD_RESULT;
|
|
37804
|
+
const realized = hasAmount3(input.monetaryProjection) ? input.monetaryProjection : null;
|
|
37805
|
+
const goal = resolveGoalAmount(input);
|
|
37806
|
+
if (realized == null || goal == null) return WITHHELD_RESULT;
|
|
37807
|
+
const variance = subtractDecimals(realized, goal);
|
|
37808
|
+
if (variance == null) return WITHHELD_RESULT;
|
|
37809
|
+
const varCents = decimalStringToCents(variance);
|
|
37810
|
+
const goalCents = decimalStringToCents(goal);
|
|
37811
|
+
if (varCents == null) return WITHHELD_RESULT;
|
|
37812
|
+
const pct = goalCents != null && goalCents !== 0n ? computeDeltaPct(realized, goal) : null;
|
|
37813
|
+
const verdict = varCents > 0n ? "above" : varCents < 0n ? "below" : "onTarget";
|
|
37814
|
+
return { verdict, variance, pct };
|
|
37815
|
+
}
|
|
37816
|
+
var DEFAULT_CHIP2 = {
|
|
37817
|
+
overBg: "#fee2e2",
|
|
37818
|
+
overText: "#b91c1c",
|
|
37819
|
+
underBg: "#dcfce7",
|
|
37820
|
+
underText: "#15803d",
|
|
37821
|
+
neutralBg: "#f1f5f9",
|
|
37822
|
+
neutralText: "#64748b"
|
|
37823
|
+
};
|
|
37824
|
+
var CHIP_BASE2 = "border-radius:999px;padding:2px 10px;font:700 11px Nunito,sans-serif;white-space:nowrap;display:inline-flex;align-items:center;gap:4px;";
|
|
37825
|
+
function buildMoneyVarianceHTML(input, chipColors = DEFAULT_CHIP2) {
|
|
37826
|
+
const r = computeMoneyVariance(input);
|
|
37827
|
+
if (r.verdict === "withheld") {
|
|
37828
|
+
return `<span data-money-variance="withheld" style="background:${chipColors.neutralBg};color:${chipColors.neutralText};${CHIP_BASE2}">${VARIANCE_LABEL_WITHHELD}</span>`;
|
|
37829
|
+
}
|
|
37830
|
+
const amount = hasAmount3(r.variance) ? formatBRLDelta(r.variance) : DASH;
|
|
37831
|
+
const pctTxt = r.pct == null ? "" : ` · ${formatDeltaPct(r.pct)}`;
|
|
37832
|
+
if (r.verdict === "above") {
|
|
37833
|
+
return `<span data-money-variance="above" title="${VARIANCE_LABEL_ABOVE}" style="background:${chipColors.overBg};color:${chipColors.overText};${CHIP_BASE2}">↑ ${VARIANCE_LABEL_ABOVE} ${amount}${pctTxt}</span>`;
|
|
37834
|
+
}
|
|
37835
|
+
if (r.verdict === "below") {
|
|
37836
|
+
return `<span data-money-variance="below" title="${VARIANCE_LABEL_BELOW}" style="background:${chipColors.underBg};color:${chipColors.underText};${CHIP_BASE2}">↓ ${VARIANCE_LABEL_BELOW} ${amount}${pctTxt}</span>`;
|
|
37837
|
+
}
|
|
37838
|
+
return `<span data-money-variance="ontarget" title="${VARIANCE_LABEL_ONTARGET}" style="background:${chipColors.neutralBg};color:${chipColors.neutralText};${CHIP_BASE2}">≈ ${VARIANCE_LABEL_ONTARGET} ${amount}${pctTxt}</span>`;
|
|
37839
|
+
}
|
|
37840
|
+
function renderMoneyVariance(options) {
|
|
37841
|
+
if (!options) return null;
|
|
37842
|
+
const hasOverlay = !!options.overlay && typeof options.overlay.state === "string";
|
|
37843
|
+
const hasAnyAmount = hasAmount3(options.monetaryProjection) || hasAmount3(options.currencyBudget);
|
|
37844
|
+
if (!hasOverlay && !hasAnyAmount && options.withheld !== true) return null;
|
|
37845
|
+
const doc = options.document || (typeof document !== "undefined" ? document : void 0);
|
|
37846
|
+
if (!doc) {
|
|
37847
|
+
throw new Error(
|
|
37848
|
+
"renderMoneyVariance requires a document (pass options.document in non-DOM envs)."
|
|
37849
|
+
);
|
|
37850
|
+
}
|
|
37851
|
+
const chipColors = { ...DEFAULT_CHIP2, ...options.chipColors };
|
|
37852
|
+
const root = doc.createElement("div");
|
|
37853
|
+
root.className = "myio-money-variance";
|
|
37854
|
+
root.setAttribute("data-money-variance-row", "1");
|
|
37855
|
+
const label = hasAmount3(options.label) ? `<span class="myio-money-variance__label" style="font:600 11px Nunito,sans-serif;color:var(--gc-muted, #64748b);margin-right:6px;">${escapeText(
|
|
37856
|
+
options.label
|
|
37857
|
+
)}</span>` : "";
|
|
37858
|
+
root.innerHTML = `<div style="display:inline-flex;align-items:center;flex-wrap:wrap;gap:4px;">` + label + buildMoneyVarianceHTML(options, chipColors) + `</div>`;
|
|
37859
|
+
return root;
|
|
37860
|
+
}
|
|
37861
|
+
function escapeText(s) {
|
|
37862
|
+
return String(s ?? "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
37863
|
+
}
|
|
37864
|
+
var DISABLED_COLUMN2 = {
|
|
37865
|
+
enabled: false,
|
|
37866
|
+
headerCellHTML: () => "",
|
|
37867
|
+
bodyCellHTML: () => "",
|
|
37868
|
+
cellValueHTML: () => ""
|
|
37869
|
+
};
|
|
37870
|
+
function createMoneyVarianceColumn(config2) {
|
|
37871
|
+
if (!config2 || typeof config2.overlay?.state !== "string" || !config2.perDeviceGoal) {
|
|
37872
|
+
return DISABLED_COLUMN2;
|
|
37873
|
+
}
|
|
37874
|
+
const overlay = config2.overlay;
|
|
37875
|
+
const perDeviceRealized = config2.perDeviceRealized || {};
|
|
37876
|
+
const perDeviceGoal = config2.perDeviceGoal || {};
|
|
37877
|
+
const label = config2.headerLabel || MONEY_VARIANCE_HEADER;
|
|
37878
|
+
const chipColors = { ...DEFAULT_CHIP2, ...config2.chipColors };
|
|
37879
|
+
const chipFor = (deviceId) => {
|
|
37880
|
+
const id = hasAmount3(deviceId) ? deviceId : null;
|
|
37881
|
+
return buildMoneyVarianceHTML(
|
|
37882
|
+
{
|
|
37883
|
+
overlay,
|
|
37884
|
+
monetaryProjection: id ? perDeviceRealized[id] : null,
|
|
37885
|
+
currencyBudget: id ? perDeviceGoal[id] : null
|
|
37886
|
+
},
|
|
37887
|
+
chipColors
|
|
37888
|
+
);
|
|
37889
|
+
};
|
|
37890
|
+
return {
|
|
37891
|
+
enabled: true,
|
|
37892
|
+
headerCellHTML: () => `<th data-money-variance-col="1" style="text-align:right;white-space:nowrap;">${label}</th>`,
|
|
37893
|
+
bodyCellHTML: (deviceId) => `<td data-money-variance-col="1" data-label="${label}" style="text-align:right;">${chipFor(
|
|
37894
|
+
deviceId
|
|
37895
|
+
)}</td>`,
|
|
37896
|
+
cellValueHTML: (deviceId) => chipFor(deviceId)
|
|
37897
|
+
};
|
|
37898
|
+
}
|
|
37899
|
+
|
|
37059
37900
|
// src/components/premium-modals/report-all/AllReportModal.ts
|
|
37060
37901
|
var DOMAIN_CONFIG2 = {
|
|
37061
37902
|
energy: {
|
|
@@ -37088,6 +37929,18 @@ var AllReportModal = class {
|
|
|
37088
37929
|
const domain = params.domain || "energy";
|
|
37089
37930
|
this.domainConfig = DOMAIN_CONFIG2[domain];
|
|
37090
37931
|
this.debugEnabled = params.debug === 1;
|
|
37932
|
+
this.moneyColumn = createReportMoneyColumn(params.money ?? null);
|
|
37933
|
+
if (this.moneyColumn.enabled && typeof document !== "undefined") {
|
|
37934
|
+
injectCoverageStyles(document);
|
|
37935
|
+
}
|
|
37936
|
+
this.varianceColumn = createMoneyVarianceColumn(
|
|
37937
|
+
params.money && params.money.perDeviceGoal ? {
|
|
37938
|
+
overlay: params.money.overlay,
|
|
37939
|
+
perDeviceRealized: params.money.perDevice,
|
|
37940
|
+
perDeviceGoal: params.money.perDeviceGoal,
|
|
37941
|
+
headerLabel: params.money.varianceHeaderLabel
|
|
37942
|
+
} : null
|
|
37943
|
+
);
|
|
37091
37944
|
this.debugLog("\u{1F680} AllReportModal initialized", {
|
|
37092
37945
|
customerId: params.customerId,
|
|
37093
37946
|
itemsListLength: params.itemsList?.length || 0,
|
|
@@ -37142,6 +37995,12 @@ var AllReportModal = class {
|
|
|
37142
37995
|
// Footer premium: Customer · relógio · versão | Powered by MYIO | PDF/CSV/XLSX.
|
|
37143
37996
|
// Os botões de export vivem AQUI (removidos da toolbar).
|
|
37144
37997
|
modalFooter = null;
|
|
37998
|
+
// RFC-0228 A6 — R$ money column. Disabled (all fragments '') when params.money is
|
|
37999
|
+
// absent, so the table/summary stay byte-identical to the pre-A6 report.
|
|
38000
|
+
moneyColumn;
|
|
38001
|
+
// RFC-0228 A7 — per-consumer realized-vs-goal R$ variance column. Disabled (all
|
|
38002
|
+
// fragments '') when params.money.perDeviceGoal is absent → byte-identical.
|
|
38003
|
+
varianceColumn;
|
|
37145
38004
|
// Debug logging helper
|
|
37146
38005
|
debugLog(message, data) {
|
|
37147
38006
|
if (this.debugEnabled) {
|
|
@@ -37606,8 +38465,25 @@ var AllReportModal = class {
|
|
|
37606
38465
|
}
|
|
37607
38466
|
];
|
|
37608
38467
|
if (!isTemperature) kpis.push({ value: String(zeroCount), label: "Sem Consumo" });
|
|
38468
|
+
const moneyKpi = this.computeMoneyKpi();
|
|
38469
|
+
if (moneyKpi) kpis.push(moneyKpi);
|
|
37609
38470
|
return kpis;
|
|
37610
38471
|
}
|
|
38472
|
+
// RFC-0228 A6 — the "Custo projetado (R$)" summary KPI, or null when money is off.
|
|
38473
|
+
// Reuses the A6 column's honest-coverage resolution: a formatted R$ total only when
|
|
38474
|
+
// the overlay is confidently priced (DEC-8), otherwise a coverage state label.
|
|
38475
|
+
computeMoneyKpi() {
|
|
38476
|
+
if (!this.moneyColumn.enabled) return null;
|
|
38477
|
+
const rowValues = this.data.map((r) => r.id ? this.params.money?.perDevice?.[r.id] : null);
|
|
38478
|
+
const total = this.moneyColumn.resolveTotal(rowValues);
|
|
38479
|
+
if (!total) return null;
|
|
38480
|
+
const label = this.params.money?.headerLabel || "Custo projetado (R$)";
|
|
38481
|
+
if (total.kind === "amount") {
|
|
38482
|
+
return { value: total.formatted, label };
|
|
38483
|
+
}
|
|
38484
|
+
const value = total.overlay.state === "unavailable" ? "Indispon\xEDvel" : "Cobertura incompleta";
|
|
38485
|
+
return { value, label };
|
|
38486
|
+
}
|
|
37611
38487
|
renderTable() {
|
|
37612
38488
|
const container = document.getElementById("table-container");
|
|
37613
38489
|
if (!container) return;
|
|
@@ -37625,13 +38501,14 @@ var AllReportModal = class {
|
|
|
37625
38501
|
const isGrouped = paginatedData.some((r) => r.groupLabel);
|
|
37626
38502
|
const grandTotal = this.calculateTotalConsumption();
|
|
37627
38503
|
const pct = (v) => grandTotal > 0 ? `${fmtPt(v / grandTotal * 100)}%` : "\u2014";
|
|
38504
|
+
const moneyCell = (row) => this.moneyColumn.bodyCellHTML(row.id);
|
|
37628
38505
|
const tableRows = isGrouped ? this.renderGroupedRows(paginatedData, grandTotal) : paginatedData.map(
|
|
37629
38506
|
(row) => `
|
|
37630
38507
|
<tr>
|
|
37631
38508
|
<td data-label="Identificador" style="font-family: monospace; font-weight: bold; text-transform: uppercase;">${row.identifier}</td>
|
|
37632
38509
|
<td data-label="Nome"><strong>${row.name}</strong></td>
|
|
37633
38510
|
<td data-label="${this.domainConfig.label}" style="text-align: right; font-weight: bold;">${fmtPt(row.consumption)}</td>
|
|
37634
|
-
<td data-label="%" style="text-align: right; color: var(--myio-text-muted);">${pct(row.consumption)}</td>
|
|
38511
|
+
${moneyCell(row)}${this.varianceColumn.bodyCellHTML(row.id)}<td data-label="%" style="text-align: right; color: var(--myio-text-muted);">${pct(row.consumption)}</td>
|
|
37635
38512
|
</tr>
|
|
37636
38513
|
`
|
|
37637
38514
|
).join("");
|
|
@@ -37682,7 +38559,7 @@ var AllReportModal = class {
|
|
|
37682
38559
|
${this.domainConfig.label}
|
|
37683
38560
|
<span style="margin-left: 4px; opacity: ${this.getSortOpacity("consumption")};">${this.getSortIcon("consumption")}</span>
|
|
37684
38561
|
</th>
|
|
37685
|
-
<th style="text-align: right; width: 14%;">%</th>
|
|
38562
|
+
${this.moneyColumn.headerCellHTML()}${this.varianceColumn.headerCellHTML()}<th style="text-align: right; width: 14%;">%</th>
|
|
37686
38563
|
</tr>
|
|
37687
38564
|
</thead>
|
|
37688
38565
|
<tbody>${tableRows}</tbody>
|
|
@@ -37754,7 +38631,7 @@ var AllReportModal = class {
|
|
|
37754
38631
|
const groupTotal = items.reduce((s, r) => s + r.consumption, 0);
|
|
37755
38632
|
const header = `
|
|
37756
38633
|
<tr class="rp-group-header">
|
|
37757
|
-
<td colspan="4">
|
|
38634
|
+
<td colspan="${4 + (this.moneyColumn.enabled ? 1 : 0) + (this.varianceColumn.enabled ? 1 : 0)}">
|
|
37758
38635
|
${groupLabel}
|
|
37759
38636
|
<span class="rp-group-total">${items.length} dispositivos \xB7 ${fmtPt(groupTotal)} ${this.domainConfig.unit}</span>
|
|
37760
38637
|
</td>
|
|
@@ -37765,7 +38642,7 @@ var AllReportModal = class {
|
|
|
37765
38642
|
<td data-label="Identificador" style="font-family: monospace; font-weight: bold; text-transform: uppercase;">${row.identifier}</td>
|
|
37766
38643
|
<td data-label="Nome"><strong>${row.name}</strong></td>
|
|
37767
38644
|
<td data-label="${this.domainConfig.label}" style="text-align: right; font-weight: bold;">${fmtPt(row.consumption)}</td>
|
|
37768
|
-
<td data-label="%" style="text-align: right; color: var(--myio-text-muted);">${pct(row.consumption)}</td>
|
|
38645
|
+
${this.moneyColumn.bodyCellHTML(row.id)}${this.varianceColumn.bodyCellHTML(row.id)}<td data-label="%" style="text-align: right; color: var(--myio-text-muted);">${pct(row.consumption)}</td>
|
|
37769
38646
|
</tr>`
|
|
37770
38647
|
).join("");
|
|
37771
38648
|
return header + dataRows;
|
|
@@ -44098,12 +44975,12 @@ var WelcomeModalView = class _WelcomeModalView {
|
|
|
44098
44975
|
if (this.metaTipEl) this.metaTipEl.style.display = "none";
|
|
44099
44976
|
}
|
|
44100
44977
|
buildMetaTipHtml(type, card) {
|
|
44101
|
-
const
|
|
44978
|
+
const esc8 = _WelcomeModalView.escapeMetaHtml;
|
|
44102
44979
|
const chip = _WelcomeModalView.metaChip;
|
|
44103
44980
|
const meta = card.metaCounts || {};
|
|
44104
44981
|
const details = card.metaDetails || {};
|
|
44105
44982
|
const loadingBody = '<div style="opacity:.7;padding:6px 0">Carregando\u2026</div>';
|
|
44106
|
-
const header = (icon, label, count) => `<div style="font-weight:800;font-size:13px;margin-bottom:8px">${icon} ${label}${count === null || count === void 0 ? "" : ` (${count})`} \u2014 ${
|
|
44983
|
+
const header = (icon, label, count) => `<div style="font-weight:800;font-size:13px;margin-bottom:8px">${icon} ${label}${count === null || count === void 0 ? "" : ` (${count})`} \u2014 ${esc8(card.title)}</div>`;
|
|
44107
44984
|
const row = (titleHtml, subHtml) => `<div style="padding:6px 0;border-top:1px solid #334155">
|
|
44108
44985
|
<div style="font-weight:600">${titleHtml}</div>
|
|
44109
44986
|
${subHtml ? `<div style="opacity:.7">${subHtml}</div>` : ""}
|
|
@@ -44119,8 +44996,8 @@ var WelcomeModalView = class _WelcomeModalView {
|
|
|
44119
44996
|
const chips = Object.entries(byState).map(([s, n]) => chip(`${s}: ${n}`)).join("") || '<span style="opacity:.7">Sem alarmes ativos</span>';
|
|
44120
44997
|
const rows = alarms.slice(0, 10).map(
|
|
44121
44998
|
(a) => row(
|
|
44122
|
-
|
|
44123
|
-
`${
|
|
44999
|
+
esc8(a.deviceName ? `${a.deviceName} \u2014 ${a.title || "Alarme"}` : a.title || "Alarme"),
|
|
45000
|
+
`${esc8(a.severity || "")} \xB7 ${esc8(a.state || "")}`
|
|
44124
45001
|
)
|
|
44125
45002
|
).join("");
|
|
44126
45003
|
return `${header("\u{1F6A8}", "Alarmes", meta.alarms ?? alarms.length)}<div style="margin-bottom:6px">${chips}</div>${rows}`;
|
|
@@ -44140,14 +45017,14 @@ var WelcomeModalView = class _WelcomeModalView {
|
|
|
44140
45017
|
const rows = annotations.slice(0, 10).map((a) => {
|
|
44141
45018
|
const when = a.createdAt ? new Date(a.createdAt).toLocaleDateString("pt-BR") : "";
|
|
44142
45019
|
const text2 = a.text.length > 90 ? `${a.text.slice(0, 90)}\u2026` : a.text;
|
|
44143
|
-
return row(
|
|
45020
|
+
return row(esc8(a.deviceLabel || "Dispositivo"), `${esc8(text2)}${when ? ` \xB7 ${esc8(when)}` : ""}`);
|
|
44144
45021
|
}).join("");
|
|
44145
45022
|
return `${header("\u{1F4CB}", "Anota\xE7\xF5es", meta.annotations ?? annotations.length)}<div style="margin-bottom:6px">${chips}</div>${rows}`;
|
|
44146
45023
|
}
|
|
44147
45024
|
if (type === "users") {
|
|
44148
45025
|
if (meta.users === null) return header("\u{1F465}", "Usu\xE1rios") + loadingBody;
|
|
44149
45026
|
const users = details.users || [];
|
|
44150
|
-
const rows = users.slice(0, 10).map((u) => row(
|
|
45027
|
+
const rows = users.slice(0, 10).map((u) => row(esc8(u.name), esc8(u.email || ""))).join("") || '<div style="opacity:.7;padding:6px 0">Sem usu\xE1rios</div>';
|
|
44151
45028
|
const more = users.length > 10 ? `<div style="opacity:.7;padding:6px 0 0">\u2026 e mais ${users.length - 10}</div>` : "";
|
|
44152
45029
|
return `${header("\u{1F465}", "Usu\xE1rios", meta.users ?? users.length)}${rows}${more}`;
|
|
44153
45030
|
}
|
|
@@ -56547,7 +57424,7 @@ var IMPORTANCE_COLORS2 = {
|
|
|
56547
57424
|
5: "#ff7675"
|
|
56548
57425
|
};
|
|
56549
57426
|
var ORDERED_TYPES = ["observation", "pending", "maintenance", "activity"];
|
|
56550
|
-
function
|
|
57427
|
+
function esc2(s) {
|
|
56551
57428
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
56552
57429
|
}
|
|
56553
57430
|
function fmtDt(iso) {
|
|
@@ -56577,11 +57454,11 @@ function renderCard(ann) {
|
|
|
56577
57454
|
<span class="adm-annot-imp-badge" style="background:${ic};color:${darkText ? "#fff" : "#333"}" title="${IMPORTANCE_LABELS2[ann.importance]}">${stars}</span>
|
|
56578
57455
|
${ann.archived ? '<span class="adm-annot-archived-badge">Arquivada</span>' : ""}
|
|
56579
57456
|
</div>
|
|
56580
|
-
<div class="adm-annot-card-text">${
|
|
57457
|
+
<div class="adm-annot-card-text">${esc2(ann.text)}</div>
|
|
56581
57458
|
${ann.dueDate ? `<div class="adm-annot-due">\u23F0 Prazo: ${new Date(ann.dueDate).toLocaleDateString("pt-BR")}</div>` : ""}
|
|
56582
57459
|
<div class="adm-annot-card-meta">
|
|
56583
57460
|
<div class="adm-annot-avatar">${ini}</div>
|
|
56584
|
-
<span class="adm-annot-author">${
|
|
57461
|
+
<span class="adm-annot-author">${esc2(ann.createdBy)}</span>
|
|
56585
57462
|
<span class="adm-annot-date">${fmtDt(ann.createdAt)}</span>
|
|
56586
57463
|
</div>
|
|
56587
57464
|
${!ann.archived ? `<div class="adm-annot-actions">
|
|
@@ -56609,7 +57486,7 @@ function renderForm(editAnn) {
|
|
|
56609
57486
|
<div class="adm-annot-form" data-edit-id="${editAnn?.id ?? ""}">
|
|
56610
57487
|
<div class="adm-annot-form-title">${editAnn ? "\u270F\uFE0F Editar Anota\xE7\xE3o" : "\u270F\uFE0F Nova Anota\xE7\xE3o"}</div>
|
|
56611
57488
|
<textarea class="adm-annot-textarea" id="admAnnotText" maxlength="255"
|
|
56612
|
-
placeholder="Digite sua anota\xE7\xE3o (m\xE1x. 255 caracteres)...">${editAnn ?
|
|
57489
|
+
placeholder="Digite sua anota\xE7\xE3o (m\xE1x. 255 caracteres)...">${editAnn ? esc2(editAnn.text) : ""}</textarea>
|
|
56613
57490
|
<div class="adm-annot-char-count"><span id="admAnnotCC">${editAnn ? editAnn.text.length : 0}</span> / 255</div>
|
|
56614
57491
|
<div class="adm-annot-form-row">
|
|
56615
57492
|
<div class="adm-annot-form-field">
|
|
@@ -56995,7 +57872,7 @@ function initials2(name) {
|
|
|
56995
57872
|
const parts = name.trim().split(/\s+/);
|
|
56996
57873
|
return parts.length >= 2 ? (parts[0][0] + parts[parts.length - 1][0]).toUpperCase() : name.substring(0, 2).toUpperCase();
|
|
56997
57874
|
}
|
|
56998
|
-
function
|
|
57875
|
+
function esc3(s) {
|
|
56999
57876
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
57000
57877
|
}
|
|
57001
57878
|
function buildTooltipHtml(annotations) {
|
|
@@ -57016,11 +57893,11 @@ function buildTooltipHtml(annotations) {
|
|
|
57016
57893
|
<span class="annot-tooltip__type-badge" style="background:${tc}18;color:${tc};border:1px solid ${tc}40">${TYPE_LABELS2[ann.type]}</span>
|
|
57017
57894
|
<span class="annot-tooltip__stars" style="color:${ic}">${stars}</span>
|
|
57018
57895
|
</div>
|
|
57019
|
-
<div class="annot-tooltip__text">${
|
|
57896
|
+
<div class="annot-tooltip__text">${esc3(ann.text)}</div>
|
|
57020
57897
|
${ann.dueDate ? `<div class="annot-tooltip__due">\u23F0 Prazo: ${new Date(ann.dueDate).toLocaleDateString("pt-BR")}</div>` : ""}
|
|
57021
57898
|
<div class="annot-tooltip__meta">
|
|
57022
57899
|
<span class="annot-tooltip__avatar">${ini}</span>
|
|
57023
|
-
<span class="annot-tooltip__author">${
|
|
57900
|
+
<span class="annot-tooltip__author">${esc3(ann.createdBy)}</span>
|
|
57024
57901
|
<span class="annot-tooltip__date">${fmtDt2(ann.createdAt)}</span>
|
|
57025
57902
|
</div>
|
|
57026
57903
|
</div>`;
|
|
@@ -70671,7 +71548,7 @@ function buildYearOptions() {
|
|
|
70671
71548
|
for (let y = now + 2; y >= now - 2; y--) out.push(y);
|
|
70672
71549
|
return out;
|
|
70673
71550
|
}
|
|
70674
|
-
function
|
|
71551
|
+
function esc4(s) {
|
|
70675
71552
|
return String(s == null ? "" : s).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
70676
71553
|
}
|
|
70677
71554
|
function openGoalsPanel(params) {
|
|
@@ -71467,13 +72344,13 @@ function openGoalsPanel(params) {
|
|
|
71467
72344
|
const g = state6.goals || {};
|
|
71468
72345
|
const parts = [];
|
|
71469
72346
|
if (hasCoverageGaps(g.coverageGaps)) {
|
|
71470
|
-
parts.push(`<p style="margin:0 0 8px;">${
|
|
72347
|
+
parts.push(`<p style="margin:0 0 8px;">${esc4(buildCoverageWarningTextPtBR(g.coverageGaps, "GERAL"))}</p>`);
|
|
71471
72348
|
}
|
|
71472
72349
|
(Array.isArray(g.devices) ? g.devices : []).forEach((d) => {
|
|
71473
72350
|
if (!hasCoverageGaps(d && d.coverageGaps)) return;
|
|
71474
72351
|
const label = d.label || d.code || "medidor";
|
|
71475
72352
|
parts.push(
|
|
71476
|
-
`<p style="margin:0 0 8px;">${
|
|
72353
|
+
`<p style="margin:0 0 8px;">${esc4(buildCoverageWarningTextPtBR(d.coverageGaps, `do medidor ${label}`))}</p>`
|
|
71477
72354
|
);
|
|
71478
72355
|
});
|
|
71479
72356
|
return `<div style="font-size:12px;line-height:1.55;color:#334155;">${parts.join("")}</div>`;
|
|
@@ -71513,7 +72390,7 @@ function openGoalsPanel(params) {
|
|
|
71513
72390
|
html += `<div class="myio-goals-alert myio-goals-alert-amber">${icon("alert")} ${i18n2.versionConflict}</div>`;
|
|
71514
72391
|
}
|
|
71515
72392
|
if (state6.saveError && !state6.conflict) {
|
|
71516
|
-
html += `<div class="myio-goals-alert myio-goals-alert-red">${icon("alert")} ${
|
|
72393
|
+
html += `<div class="myio-goals-alert myio-goals-alert-red">${icon("alert")} ${esc4(state6.saveError)}</div>`;
|
|
71517
72394
|
}
|
|
71518
72395
|
if (state6.saved && !state6.saveError) {
|
|
71519
72396
|
html += `<div class="myio-goals-alert myio-goals-alert-green">${icon("check")} ${i18n2.saveSuccess}</div>`;
|
|
@@ -71528,7 +72405,7 @@ function openGoalsPanel(params) {
|
|
|
71528
72405
|
return `
|
|
71529
72406
|
<div class="myio-goals-center myio-goals-center-col">
|
|
71530
72407
|
${icon("alert-lg")}
|
|
71531
|
-
<p>${
|
|
72408
|
+
<p>${esc4(state6.error)}</p>
|
|
71532
72409
|
<button class="myio-goals-btn myio-goals-btn-outline" data-action="retry">${i18n2.retry}</button>
|
|
71533
72410
|
</div>`;
|
|
71534
72411
|
}
|
|
@@ -71618,7 +72495,7 @@ function openGoalsPanel(params) {
|
|
|
71618
72495
|
const cellLabel = state6.level === "month" ? i18n2.months[key] : state6.level === "day" ? i18n2.dayCell.replace("{day}", Number(key)) : `${key}:00`;
|
|
71619
72496
|
const canDrill = state6.level !== "hour";
|
|
71620
72497
|
const labelEl = canDrill ? `<button class="myio-goals-cell-drill" data-action="${state6.level === "month" ? "open-month" : "open-day"}" data-key="${key}" title="${i18n2.drill.openTitle}">${cellLabel} ${icon("chevron-sm")}</button>` : `<span class="myio-goals-cell-label">${cellLabel}</span>`;
|
|
71621
|
-
const val = state6.draft[key] !== void 0 ?
|
|
72498
|
+
const val = state6.draft[key] !== void 0 ? esc4(state6.draft[key]) : "";
|
|
71622
72499
|
const minAttr = cfg.allowsNegative ? "" : 'min="0"';
|
|
71623
72500
|
return `
|
|
71624
72501
|
<div class="myio-goals-cell">
|
|
@@ -71686,7 +72563,7 @@ function openGoalsPanel(params) {
|
|
|
71686
72563
|
const actor = ev.actor ? `${String(ev.actor).slice(0, 8)}\u2026` : i18n2.history.system;
|
|
71687
72564
|
const extra = ev.bucketCount - (ev.details ? ev.details.length : 0);
|
|
71688
72565
|
const chips = (ev.details || []).slice(0, DETAIL_PREVIEW).map(
|
|
71689
|
-
(d) => `<span class="myio-goals-tl-chip"><span class="myio-goals-tl-ref">${
|
|
72566
|
+
(d) => `<span class="myio-goals-tl-chip"><span class="myio-goals-tl-ref">${esc4(formatRef(d.ref))}</span>${d.value === null ? "\u2014" : fmt2(d.value)}</span>`
|
|
71690
72567
|
).join("");
|
|
71691
72568
|
const more = extra > 0 ? `<span class="myio-goals-tl-more">${i18n2.history.moreDetails.replace("{n}", extra)}</span>` : "";
|
|
71692
72569
|
return `
|
|
@@ -71696,7 +72573,7 @@ function openGoalsPanel(params) {
|
|
|
71696
72573
|
<span class="myio-goals-tl-title">${i18n2.history.source[ev.source] || i18n2.history.source.EDIT}</span>
|
|
71697
72574
|
<span class="myio-goals-tl-ver">v${ev.version}</span>
|
|
71698
72575
|
</div>
|
|
71699
|
-
<p class="myio-goals-tl-meta" title="${
|
|
72576
|
+
<p class="myio-goals-tl-meta" title="${esc4(new Date(ev.changedAt).toLocaleString(locale))}">${esc4(actor)} \xB7 ${esc4(timeAgo(ev.changedAt))}</p>
|
|
71700
72577
|
<p class="myio-goals-tl-records">${i18n2.history.records.replace("{n}", ev.bucketCount)} \xB7 ${i18n2.levels[ev.actionLevel] || ev.actionLevel}</p>
|
|
71701
72578
|
${chips || more ? `<div class="myio-goals-tl-chips">${chips}${more}</div>` : ""}
|
|
71702
72579
|
</li>`;
|
|
@@ -71743,7 +72620,7 @@ ${state6.year}-03-15T08,15`;
|
|
|
71743
72620
|
let html = `
|
|
71744
72621
|
<div class="myio-goals-import-hint">
|
|
71745
72622
|
<p>${i18n2.import.formatHint}</p>
|
|
71746
|
-
<code>${
|
|
72623
|
+
<code>${esc4(sample)}</code>
|
|
71747
72624
|
</div>`;
|
|
71748
72625
|
if (!applied) {
|
|
71749
72626
|
html += `
|
|
@@ -71757,16 +72634,16 @@ ${state6.year}-03-15T08,15`;
|
|
|
71757
72634
|
<input type="file" id="myio-goals-csv-file" accept=".csv,.txt,text/csv,text/plain" style="display:none" />
|
|
71758
72635
|
</div>
|
|
71759
72636
|
</div>
|
|
71760
|
-
<textarea id="myio-goals-csv-textarea" rows="8" spellcheck="false" placeholder="${
|
|
72637
|
+
<textarea id="myio-goals-csv-textarea" rows="8" spellcheck="false" placeholder="${esc4(`bucket,value
|
|
71761
72638
|
${state6.year},100000
|
|
71762
72639
|
${state6.year}-03,9000
|
|
71763
72640
|
${state6.year}-03-15,310
|
|
71764
|
-
${state6.year}-03-15T08,15`)}">${
|
|
72641
|
+
${state6.year}-03-15T08,15`)}">${esc4(state6.csv)}</textarea>
|
|
71765
72642
|
<p class="myio-goals-microhint">${i18n2.import.unitNote.replace("{unit}", unitLabel2())}</p>
|
|
71766
72643
|
</div>`;
|
|
71767
72644
|
}
|
|
71768
72645
|
if (state6.saveError && state6.conflictVersion === null) {
|
|
71769
|
-
html += `<div class="myio-goals-alert myio-goals-alert-red">${icon("alert")} ${
|
|
72646
|
+
html += `<div class="myio-goals-alert myio-goals-alert-red">${icon("alert")} ${esc4(state6.saveError)}</div>`;
|
|
71770
72647
|
}
|
|
71771
72648
|
if (state6.conflictVersion !== null) {
|
|
71772
72649
|
html += `<div class="myio-goals-alert myio-goals-alert-amber">${icon("alert")} ${i18n2.import.conflict}</div>`;
|
|
@@ -71795,7 +72672,7 @@ ${state6.year}-03-15T08,15`)}">${esc3(state6.csv)}</textarea>
|
|
|
71795
72672
|
<div class="myio-goals-import-diags">
|
|
71796
72673
|
<p class="myio-goals-import-diags-title">${i18n2.import.diagnosticsTitle}</p>
|
|
71797
72674
|
<ul>${result.diagnostics.map(
|
|
71798
|
-
(d) => `<li>${icon("alert-sm")} <span><span class="myio-goals-diag-line">${i18n2.import.line.replace("{line}", d.line)}</span>${d.bucket ? ` <span class="myio-goals-diag-bucket">[${
|
|
72675
|
+
(d) => `<li>${icon("alert-sm")} <span><span class="myio-goals-diag-line">${i18n2.import.line.replace("{line}", d.line)}</span>${d.bucket ? ` <span class="myio-goals-diag-bucket">[${esc4(d.bucket)}]</span>` : ""} ${esc4(d.reason)}</span></li>`
|
|
71799
72676
|
).join("")}</ul>
|
|
71800
72677
|
</div>`;
|
|
71801
72678
|
}
|
|
@@ -71803,7 +72680,7 @@ ${state6.year}-03-15T08,15`)}">${esc3(state6.csv)}</textarea>
|
|
|
71803
72680
|
html += `
|
|
71804
72681
|
<div class="myio-goals-import-log">
|
|
71805
72682
|
<p class="myio-goals-import-log-title">${i18n2.import.logTitle}</p>
|
|
71806
|
-
<ul>${result.log.map((line) => `<li>${
|
|
72683
|
+
<ul>${result.log.map((line) => `<li>${esc4(line)}</li>`).join("")}</ul>
|
|
71807
72684
|
</div>`;
|
|
71808
72685
|
}
|
|
71809
72686
|
html += `</div>`;
|
|
@@ -75545,6 +76422,26 @@ var EnergySummaryTooltip = {
|
|
|
75545
76422
|
}
|
|
75546
76423
|
return formatConsumption3(summary.totalConsumption, unit);
|
|
75547
76424
|
},
|
|
76425
|
+
/**
|
|
76426
|
+
* RFC-0228 A6 — the R$ figure shown beside "Consumo Total", or `''` when no money
|
|
76427
|
+
* overlay is present (gate off → byte-identical to the pre-A6 tooltip).
|
|
76428
|
+
*
|
|
76429
|
+
* DEC-8 (GCDR RFC-0054): clients consume the backend decimal string and never
|
|
76430
|
+
* re-derive. When the overlay is confidently priced this shows the backend
|
|
76431
|
+
* aggregate verbatim; otherwise it shows A4's honest coverage indicator — never a
|
|
76432
|
+
* fabricated R$ 0. Amounts are formatted string-in/string-out via A2a/F0.
|
|
76433
|
+
*/
|
|
76434
|
+
formatMoneyTotal(summary) {
|
|
76435
|
+
const money = summary.money;
|
|
76436
|
+
const column = createReportMoneyColumn(
|
|
76437
|
+
money ? { overlay: money.overlay, perDevice: money.perDevice || {}, total: money.total, variance: money.variance } : null
|
|
76438
|
+
);
|
|
76439
|
+
if (!column.enabled) return "";
|
|
76440
|
+
if (typeof document !== "undefined") injectCoverageStyles(document);
|
|
76441
|
+
const rowValues = money?.perDevice ? Object.values(money.perDevice) : [];
|
|
76442
|
+
const inner = column.totalHTML(rowValues);
|
|
76443
|
+
return `<div class="energy-summary-tooltip__total energy-summary-tooltip__total--money" data-money-total-row="1"><span class="energy-summary-tooltip__total-label">Custo projetado (R$)</span><span class="energy-summary-tooltip__total-value">${inner}</span></div>`;
|
|
76444
|
+
},
|
|
75548
76445
|
/**
|
|
75549
76446
|
* Render shopping view rows (for "Por Shopping" tab)
|
|
75550
76447
|
* Shows device count and consumption breakdown by shopping with expandable subcategories
|
|
@@ -75699,7 +76596,7 @@ var EnergySummaryTooltip = {
|
|
|
75699
76596
|
<div class="energy-summary-tooltip__total">
|
|
75700
76597
|
<span class="energy-summary-tooltip__total-label">Consumo Total</span>
|
|
75701
76598
|
<span class="energy-summary-tooltip__total-value">${this.formatTotalWithFilter(summary)}</span>
|
|
75702
|
-
</div
|
|
76599
|
+
</div>${this.formatMoneyTotal(summary)}
|
|
75703
76600
|
</div>
|
|
75704
76601
|
`;
|
|
75705
76602
|
},
|
|
@@ -78624,7 +79521,7 @@ function injectCSS10() {
|
|
|
78624
79521
|
document.head.appendChild(style);
|
|
78625
79522
|
_cssInjected2 = true;
|
|
78626
79523
|
}
|
|
78627
|
-
function
|
|
79524
|
+
function esc5(value) {
|
|
78628
79525
|
return String(value == null ? "" : value).replace(
|
|
78629
79526
|
/[&<>"]/g,
|
|
78630
79527
|
(c) => ({ "&": "&", "<": "<", ">": ">", '"': """ })[c]
|
|
@@ -78674,7 +79571,7 @@ function buildPieSvg(visible, total) {
|
|
|
78674
79571
|
const val = Number(v.d.value) || 0;
|
|
78675
79572
|
return `<svg class="myio-col-summary__pie" viewBox="0 0 220 220">
|
|
78676
79573
|
<circle class="myio-col-summary__slice" data-idx="${v.idx}" cx="110" cy="110" r="100"
|
|
78677
|
-
fill="${sliceColor(v.idx)}"><title>${
|
|
79574
|
+
fill="${sliceColor(v.idx)}"><title>${esc5(v.d.name)} \u2014 ${esc5(fmt2(val))} (${fmtPct2(
|
|
78678
79575
|
val,
|
|
78679
79576
|
total,
|
|
78680
79577
|
pd
|
|
@@ -78689,7 +79586,7 @@ function buildPieSvg(visible, total) {
|
|
|
78689
79586
|
const a1 = acc / total * 360;
|
|
78690
79587
|
return `<path class="myio-col-summary__slice" data-idx="${v.idx}"
|
|
78691
79588
|
d="${arcPath(110, 110, 100, a0, a1)}" fill="${sliceColor(v.idx)}"
|
|
78692
|
-
><title>${
|
|
79589
|
+
><title>${esc5(v.d.name)} \u2014 ${esc5(fmt2(val))} (${fmtPct2(val, total, pd)})</title></path>`;
|
|
78693
79590
|
}).join("");
|
|
78694
79591
|
return `<svg class="myio-col-summary__pie" viewBox="0 0 220 220">${paths}</svg>`;
|
|
78695
79592
|
}
|
|
@@ -78703,8 +79600,8 @@ function buildLegend(total) {
|
|
|
78703
79600
|
return `<div class="myio-col-summary__legend-row${isExcl ? " is-excluded" : ""}" data-idx="${idx}"
|
|
78704
79601
|
title="Clique para ${isExcl ? "incluir" : "remover"} da pizza">
|
|
78705
79602
|
<span class="myio-col-summary__legend-dot" style="background:${sliceColor(idx)};"></span>
|
|
78706
|
-
<span class="myio-col-summary__legend-name">${
|
|
78707
|
-
<span class="myio-col-summary__legend-val">${
|
|
79603
|
+
<span class="myio-col-summary__legend-name">${esc5(d.name)}</span>
|
|
79604
|
+
<span class="myio-col-summary__legend-val">${esc5(fmt2(val))}</span>
|
|
78708
79605
|
<span class="myio-col-summary__legend-pct">${pct}</span>
|
|
78709
79606
|
</div>`;
|
|
78710
79607
|
}).join("");
|
|
@@ -78719,7 +79616,7 @@ function buildInner() {
|
|
|
78719
79616
|
const avg = count ? total / count : 0;
|
|
78720
79617
|
const periodRow = data.periodLabel ? `<div class="myio-col-summary__kpi">
|
|
78721
79618
|
<span class="myio-col-summary__kpi-label">Per\xEDodo</span>
|
|
78722
|
-
<span class="myio-col-summary__kpi-value">${
|
|
79619
|
+
<span class="myio-col-summary__kpi-value">${esc5(data.periodLabel)}</span>
|
|
78723
79620
|
</div>` : "";
|
|
78724
79621
|
const kpis = `<div class="myio-col-summary__kpis">
|
|
78725
79622
|
${periodRow}
|
|
@@ -78729,13 +79626,13 @@ function buildInner() {
|
|
|
78729
79626
|
</div>
|
|
78730
79627
|
<div class="myio-col-summary__kpi">
|
|
78731
79628
|
<span class="myio-col-summary__kpi-label">Consumo m\xE9dio</span>
|
|
78732
|
-
<span class="myio-col-summary__kpi-value myio-col-summary__kpi-value--accent">${
|
|
79629
|
+
<span class="myio-col-summary__kpi-value myio-col-summary__kpi-value--accent">${esc5(
|
|
78733
79630
|
fmt2(avg)
|
|
78734
79631
|
)}</span>
|
|
78735
79632
|
</div>
|
|
78736
79633
|
<div class="myio-col-summary__kpi">
|
|
78737
79634
|
<span class="myio-col-summary__kpi-label">Consumo total</span>
|
|
78738
|
-
<span class="myio-col-summary__kpi-value">${
|
|
79635
|
+
<span class="myio-col-summary__kpi-value">${esc5(fmt2(total))}</span>
|
|
78739
79636
|
</div>
|
|
78740
79637
|
</div>`;
|
|
78741
79638
|
if (!data.devices.length) {
|
|
@@ -78749,8 +79646,8 @@ function buildInner() {
|
|
|
78749
79646
|
).slice(0, 3);
|
|
78750
79647
|
const row = (v) => `
|
|
78751
79648
|
<div class="myio-col-summary__row">
|
|
78752
|
-
<span class="myio-col-summary__name" title="${
|
|
78753
|
-
<span class="myio-col-summary__val">${
|
|
79649
|
+
<span class="myio-col-summary__name" title="${esc5(v.d.name)}">${esc5(v.d.name)}</span>
|
|
79650
|
+
<span class="myio-col-summary__val">${esc5(fmt2(Number(v.d.value) || 0))}</span>
|
|
78754
79651
|
<span class="myio-col-summary__pct">${fmtPct2(Number(v.d.value) || 0, total, pd)}</span>
|
|
78755
79652
|
</div>`;
|
|
78756
79653
|
const group = (label, list) => list.length ? `<div class="myio-col-summary__group">
|
|
@@ -78773,7 +79670,7 @@ function buildInner() {
|
|
|
78773
79670
|
</div>
|
|
78774
79671
|
<div class="myio-col-summary__footer">
|
|
78775
79672
|
<span class="myio-col-summary__footer-label">Consumo Total \xB7 ${count} dispositivos</span>
|
|
78776
|
-
<span class="myio-col-summary__footer-value">${
|
|
79673
|
+
<span class="myio-col-summary__footer-value">${esc5(fmt2(total))}</span>
|
|
78777
79674
|
</div>`;
|
|
78778
79675
|
}
|
|
78779
79676
|
function setHighlight(idx) {
|
|
@@ -86553,7 +87450,7 @@ function injectStyles11(doc) {
|
|
|
86553
87450
|
`;
|
|
86554
87451
|
(doc.head || doc.documentElement).appendChild(s);
|
|
86555
87452
|
}
|
|
86556
|
-
function
|
|
87453
|
+
function esc6(v) {
|
|
86557
87454
|
return String(v ?? "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
86558
87455
|
}
|
|
86559
87456
|
function fmtPct3(pct) {
|
|
@@ -86574,8 +87471,8 @@ function renderDeltaChip(delta) {
|
|
|
86574
87471
|
const tone = delta.tone === "good" ? "good" : delta.tone === "bad" ? "bad" : "neutral";
|
|
86575
87472
|
const arrow = delta.arrow === "up" ? "\u2191" : delta.arrow === "down" ? "\u2193" : "\u2248";
|
|
86576
87473
|
const pctTxt = fmtPct3(Math.abs(Number(delta.pct)));
|
|
86577
|
-
const txt = delta.text ? ` ${
|
|
86578
|
-
return `<span class="myio-gbt__chip myio-gbt__chip--${tone}">${arrow} ${
|
|
87474
|
+
const txt = delta.text ? ` ${esc6(delta.text)}` : "";
|
|
87475
|
+
return `<span class="myio-gbt__chip myio-gbt__chip--${tone}">${arrow} ${esc6(pctTxt)}${txt}</span>`;
|
|
86579
87476
|
}
|
|
86580
87477
|
function renderRow(row, level) {
|
|
86581
87478
|
const hasChildren = Array.isArray(row.children) && row.children.length > 0;
|
|
@@ -86583,12 +87480,12 @@ function renderRow(row, level) {
|
|
|
86583
87480
|
const id = `gbtr-${++_rowSeq}`;
|
|
86584
87481
|
const pct = row.pct;
|
|
86585
87482
|
const caret = hasChildren ? `<button class="myio-gbt__caret${open ? " is-open" : ""}" data-caret="${id}" title="Expandir/recolher">\u25B8</button>` : `<span class="myio-gbt__caret-spacer"></span>`;
|
|
86586
|
-
const swatch = row.color ? `<span class="myio-gbt__swatch" style="background:${
|
|
86587
|
-
const icon = row.icon ? `<span class="myio-gbt__icon">${
|
|
87483
|
+
const swatch = row.color ? `<span class="myio-gbt__swatch" style="background:${esc6(row.color)}"></span>` : "";
|
|
87484
|
+
const icon = row.icon ? `<span class="myio-gbt__icon">${esc6(row.icon)}</span>` : "";
|
|
86588
87485
|
const chipHtml = row.delta ? renderDeltaChip(row.delta) : "";
|
|
86589
|
-
const pctHtml = !row.delta && pct != null && isFinite(pct) ? `<span class="myio-gbt__pct">${
|
|
87486
|
+
const pctHtml = !row.delta && pct != null && isFinite(pct) ? `<span class="myio-gbt__pct">${esc6(fmtPct3(pct))}</span>` : "";
|
|
86590
87487
|
const rowClass = level > 0 ? "myio-gbt__row myio-gbt__row--child" : "myio-gbt__row";
|
|
86591
|
-
let html = `<div class="${rowClass}">` + caret + swatch + icon + `<span class="myio-gbt__label">${
|
|
87488
|
+
let html = `<div class="${rowClass}">` + caret + swatch + icon + `<span class="myio-gbt__label">${esc6(row.label)}</span><span class="myio-gbt__value">${esc6(row.valueText)}</span>` + chipHtml + pctHtml + `</div>`;
|
|
86592
87489
|
if (hasChildren) {
|
|
86593
87490
|
const childHtml = row.children.map((c) => renderRow(c, level + 1)).join("");
|
|
86594
87491
|
html += `<div class="myio-gbt__children${open ? " is-open" : ""}" data-children="${id}">${childHtml}</div>`;
|
|
@@ -86671,8 +87568,8 @@ function createGoalsBarTooltip(opts) {
|
|
|
86671
87568
|
<div class="myio-gbt__card">
|
|
86672
87569
|
<div class="myio-gbt__header">
|
|
86673
87570
|
<div class="myio-gbt__title-wrap">
|
|
86674
|
-
<div class="myio-gbt__title">${
|
|
86675
|
-
${data.subtitle ? `<div class="myio-gbt__subtitle">${
|
|
87571
|
+
<div class="myio-gbt__title">${esc6(data.title)}</div>
|
|
87572
|
+
${data.subtitle ? `<div class="myio-gbt__subtitle">${esc6(data.subtitle)}</div>` : ""}
|
|
86676
87573
|
</div>
|
|
86677
87574
|
<button class="myio-gbt__btn myio-gbt__btn--pin${pinned ? " is-pinned" : ""}" data-action="pin" title="${pinned ? "Desafixar" : "Fixar na tela"}">\u{1F4CC}</button>
|
|
86678
87575
|
<button class="myio-gbt__btn myio-gbt__btn--close" data-action="close" title="Fechar">\u2715</button>
|
|
@@ -87681,19 +88578,19 @@ function _updateCoverageHint(topDoc) {
|
|
|
87681
88578
|
const deviceCount = data.granularity === "DEVICE" ? data.devices?.length ?? 0 : 0;
|
|
87682
88579
|
hint.textContent = `\u26A0 Meta incompleta para este dom\xEDnio/ano` + (deviceCount > 0 ? ` \xB7 Por medidor (${deviceCount})` : "") + ` \u2014 passe o mouse para detalhes`;
|
|
87683
88580
|
tabs.insertAdjacentElement("afterend", hint);
|
|
87684
|
-
const
|
|
88581
|
+
const esc8 = (s) => String(s ?? "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
87685
88582
|
try {
|
|
87686
88583
|
_coverageDetach = InfoTooltip.attach(hint, () => {
|
|
87687
88584
|
const d = _getGoalsData(_currentDomain);
|
|
87688
88585
|
const parts = [];
|
|
87689
88586
|
if (hasCoverageGaps(d?.coverageGaps)) {
|
|
87690
|
-
parts.push(`<p style="margin:0 0 8px;">${
|
|
88587
|
+
parts.push(`<p style="margin:0 0 8px;">${esc8(buildCoverageWarningTextPtBR(d?.coverageGaps, "GERAL"))}</p>`);
|
|
87691
88588
|
}
|
|
87692
88589
|
(d?.devices || []).forEach((dev) => {
|
|
87693
88590
|
if (!hasCoverageGaps(dev?.coverageGaps)) return;
|
|
87694
88591
|
const label = dev.label || dev.code || "medidor";
|
|
87695
88592
|
parts.push(
|
|
87696
|
-
`<p style="margin:0 0 8px;">${
|
|
88593
|
+
`<p style="margin:0 0 8px;">${esc8(buildCoverageWarningTextPtBR(dev.coverageGaps, `do medidor ${label}`))}</p>`
|
|
87697
88594
|
);
|
|
87698
88595
|
});
|
|
87699
88596
|
return {
|
|
@@ -90611,7 +91508,7 @@ function isPricingAllowed(email, superAdmin) {
|
|
|
90611
91508
|
const e = (email ?? "").trim().toLowerCase();
|
|
90612
91509
|
return e.endsWith("@myio.com.br");
|
|
90613
91510
|
}
|
|
90614
|
-
function
|
|
91511
|
+
function formatBRL2(value) {
|
|
90615
91512
|
if (!Number.isFinite(value)) return "";
|
|
90616
91513
|
const amount = new Intl.NumberFormat("pt-BR", {
|
|
90617
91514
|
minimumFractionDigits: 2,
|
|
@@ -91146,6 +92043,608 @@ function injectPricingPanelStyles(doc) {
|
|
|
91146
92043
|
doc.head.appendChild(style);
|
|
91147
92044
|
}
|
|
91148
92045
|
|
|
92046
|
+
// src/components/pricing-panel/tariffApiClient.ts
|
|
92047
|
+
var TariffApiError = class extends Error {
|
|
92048
|
+
code;
|
|
92049
|
+
status;
|
|
92050
|
+
details;
|
|
92051
|
+
currentVersion;
|
|
92052
|
+
constructor(code, status, message, details) {
|
|
92053
|
+
super(message || code);
|
|
92054
|
+
this.name = "TariffApiError";
|
|
92055
|
+
this.code = code;
|
|
92056
|
+
this.status = status;
|
|
92057
|
+
this.details = details;
|
|
92058
|
+
const cv = details && details.currentVersion;
|
|
92059
|
+
this.currentVersion = typeof cv === "number" ? cv : void 0;
|
|
92060
|
+
}
|
|
92061
|
+
};
|
|
92062
|
+
function joinUrl(baseUrl, basePath, path) {
|
|
92063
|
+
const b = baseUrl.replace(/\/+$/, "");
|
|
92064
|
+
const bp = basePath ? `/${basePath.replace(/^\/+|\/+$/g, "")}` : "";
|
|
92065
|
+
const p = path.startsWith("/") ? path : `/${path}`;
|
|
92066
|
+
return `${b}${bp}${p}`;
|
|
92067
|
+
}
|
|
92068
|
+
function tariffQuery(sel, granularity) {
|
|
92069
|
+
const qs = new URLSearchParams();
|
|
92070
|
+
qs.set("domain", sel.domain);
|
|
92071
|
+
qs.set("category", sel.category);
|
|
92072
|
+
qs.set("year", String(sel.year));
|
|
92073
|
+
if (granularity) qs.set("granularity", granularity);
|
|
92074
|
+
return qs.toString();
|
|
92075
|
+
}
|
|
92076
|
+
function parseETagVersion(headers) {
|
|
92077
|
+
const raw = headers.get("ETag") || headers.get("etag");
|
|
92078
|
+
if (!raw) return void 0;
|
|
92079
|
+
const m = /"?(-?\d+)"?/.exec(raw);
|
|
92080
|
+
return m ? Number(m[1]) : void 0;
|
|
92081
|
+
}
|
|
92082
|
+
var TariffApiClient = class {
|
|
92083
|
+
cfg;
|
|
92084
|
+
fetchImpl;
|
|
92085
|
+
basePath;
|
|
92086
|
+
constructor(config2) {
|
|
92087
|
+
if (!config2 || !config2.baseUrl) {
|
|
92088
|
+
throw new Error("TariffApiClient requires a baseUrl.");
|
|
92089
|
+
}
|
|
92090
|
+
this.cfg = config2;
|
|
92091
|
+
const injected = config2.fetchImpl || globalThis.fetch;
|
|
92092
|
+
if (typeof injected !== "function") {
|
|
92093
|
+
throw new Error("TariffApiClient requires a fetch implementation.");
|
|
92094
|
+
}
|
|
92095
|
+
this.fetchImpl = config2.fetchImpl ? config2.fetchImpl : injected.bind(globalThis);
|
|
92096
|
+
this.basePath = config2.basePath ?? "api/v1";
|
|
92097
|
+
}
|
|
92098
|
+
authHeaders() {
|
|
92099
|
+
const h2 = {};
|
|
92100
|
+
if (this.cfg.apiKey) h2["X-API-Key"] = this.cfg.apiKey;
|
|
92101
|
+
if (this.cfg.jwt) h2["Authorization"] = `Bearer ${this.cfg.jwt}`;
|
|
92102
|
+
if (this.cfg.tenantId) h2["X-Tenant-Id"] = this.cfg.tenantId;
|
|
92103
|
+
return h2;
|
|
92104
|
+
}
|
|
92105
|
+
/** Read the tariff tree. `granularity` defaults to `day` server-side. */
|
|
92106
|
+
async getTariff(sel, granularity = "hour") {
|
|
92107
|
+
const url = joinUrl(
|
|
92108
|
+
this.cfg.baseUrl,
|
|
92109
|
+
this.basePath,
|
|
92110
|
+
`/customers/${encodeURIComponent(sel.customerId)}/tariffs?${tariffQuery(sel, granularity)}`
|
|
92111
|
+
);
|
|
92112
|
+
const res = await this.fetchImpl(url, {
|
|
92113
|
+
method: "GET",
|
|
92114
|
+
headers: { Accept: "application/json", ...this.authHeaders() }
|
|
92115
|
+
});
|
|
92116
|
+
const body = await this.readBody(res);
|
|
92117
|
+
if (!res.ok) throw this.toError(res, body);
|
|
92118
|
+
const etagVersion = parseETagVersion(res.headers);
|
|
92119
|
+
const parsed = body || {};
|
|
92120
|
+
return {
|
|
92121
|
+
customerId: sel.customerId,
|
|
92122
|
+
domain: sel.domain,
|
|
92123
|
+
category: sel.category,
|
|
92124
|
+
year: sel.year,
|
|
92125
|
+
unit: parsed.unit,
|
|
92126
|
+
currency: parsed.currency,
|
|
92127
|
+
tariffModel: parsed.tariffModel,
|
|
92128
|
+
timezone: parsed.timezone,
|
|
92129
|
+
version: typeof parsed.version === "number" ? parsed.version : etagVersion ?? 0,
|
|
92130
|
+
tree: parsed.tree || {}
|
|
92131
|
+
};
|
|
92132
|
+
}
|
|
92133
|
+
/** REPLACE the whole year with a nested price tree. */
|
|
92134
|
+
async putTariff(sel, tree, expectedVersion) {
|
|
92135
|
+
return this.write("PUT", sel, { ...tree, ...guardBody(expectedVersion) }, expectedVersion);
|
|
92136
|
+
}
|
|
92137
|
+
/** MERGE sparse buckets into the year (finest level wins). */
|
|
92138
|
+
async patchTariff(sel, buckets, expectedVersion) {
|
|
92139
|
+
return this.write("PATCH", sel, { buckets, ...guardBody(expectedVersion) }, expectedVersion);
|
|
92140
|
+
}
|
|
92141
|
+
/**
|
|
92142
|
+
* DELETE the whole year (no `bucket`) or one sub-bucket (`bucket` present).
|
|
92143
|
+
* Whole-year delete is idempotent (204 even if absent).
|
|
92144
|
+
*/
|
|
92145
|
+
async deleteTariff(sel, opts = {}) {
|
|
92146
|
+
const hasBody = Boolean(opts.bucket) || typeof opts.expectedVersion === "number";
|
|
92147
|
+
const url = joinUrl(
|
|
92148
|
+
this.cfg.baseUrl,
|
|
92149
|
+
this.basePath,
|
|
92150
|
+
`/customers/${encodeURIComponent(sel.customerId)}/tariffs?${tariffQuery(sel)}`
|
|
92151
|
+
);
|
|
92152
|
+
const headers = { Accept: "application/json", ...this.authHeaders() };
|
|
92153
|
+
if (typeof opts.expectedVersion === "number") headers["If-Match"] = `"${opts.expectedVersion}"`;
|
|
92154
|
+
const init = { method: "DELETE", headers };
|
|
92155
|
+
if (hasBody) {
|
|
92156
|
+
headers["Content-Type"] = "application/json";
|
|
92157
|
+
init.body = JSON.stringify({
|
|
92158
|
+
...opts.bucket ? { bucket: opts.bucket } : {},
|
|
92159
|
+
...guardBody(opts.expectedVersion)
|
|
92160
|
+
});
|
|
92161
|
+
}
|
|
92162
|
+
const res = await this.fetchImpl(url, init);
|
|
92163
|
+
if (res.status === 204) return {};
|
|
92164
|
+
const body = await this.readBody(res);
|
|
92165
|
+
if (!res.ok) throw this.toError(res, body);
|
|
92166
|
+
const etagVersion = parseETagVersion(res.headers);
|
|
92167
|
+
const v = (body && body.version) ?? etagVersion;
|
|
92168
|
+
return typeof v === "number" ? { version: v } : {};
|
|
92169
|
+
}
|
|
92170
|
+
async write(method, sel, body, expectedVersion) {
|
|
92171
|
+
const url = joinUrl(
|
|
92172
|
+
this.cfg.baseUrl,
|
|
92173
|
+
this.basePath,
|
|
92174
|
+
`/customers/${encodeURIComponent(sel.customerId)}/tariffs?${tariffQuery(sel)}`
|
|
92175
|
+
);
|
|
92176
|
+
const headers = {
|
|
92177
|
+
Accept: "application/json",
|
|
92178
|
+
"Content-Type": "application/json",
|
|
92179
|
+
...this.authHeaders()
|
|
92180
|
+
};
|
|
92181
|
+
if (typeof expectedVersion === "number") headers["If-Match"] = `"${expectedVersion}"`;
|
|
92182
|
+
const res = await this.fetchImpl(url, { method, headers, body: JSON.stringify(body) });
|
|
92183
|
+
const parsed = await this.readBody(res);
|
|
92184
|
+
if (!res.ok) throw this.toError(res, parsed);
|
|
92185
|
+
const etagVersion = parseETagVersion(res.headers);
|
|
92186
|
+
const v = (parsed && parsed.version) ?? etagVersion;
|
|
92187
|
+
return { version: typeof v === "number" ? v : (expectedVersion ?? 0) + 1 };
|
|
92188
|
+
}
|
|
92189
|
+
async readBody(res) {
|
|
92190
|
+
try {
|
|
92191
|
+
const text2 = await res.text();
|
|
92192
|
+
if (!text2) return null;
|
|
92193
|
+
return JSON.parse(text2);
|
|
92194
|
+
} catch {
|
|
92195
|
+
return null;
|
|
92196
|
+
}
|
|
92197
|
+
}
|
|
92198
|
+
toError(res, body) {
|
|
92199
|
+
const err = body && body.error;
|
|
92200
|
+
if (err && typeof err === "object") {
|
|
92201
|
+
const e = err;
|
|
92202
|
+
return new TariffApiError(
|
|
92203
|
+
e.code || `HTTP_${res.status}`,
|
|
92204
|
+
res.status,
|
|
92205
|
+
e.message,
|
|
92206
|
+
e.details
|
|
92207
|
+
);
|
|
92208
|
+
}
|
|
92209
|
+
return new TariffApiError(`HTTP_${res.status}`, res.status, res.statusText);
|
|
92210
|
+
}
|
|
92211
|
+
};
|
|
92212
|
+
function guardBody(expectedVersion) {
|
|
92213
|
+
return typeof expectedVersion === "number" ? { expectedVersion } : {};
|
|
92214
|
+
}
|
|
92215
|
+
function createTariffApiClient(config2) {
|
|
92216
|
+
return new TariffApiClient(config2);
|
|
92217
|
+
}
|
|
92218
|
+
|
|
92219
|
+
// src/components/pricing-panel/tariffApiAdapter.ts
|
|
92220
|
+
var PANEL_TO_WIRE_DOMAIN = {
|
|
92221
|
+
energy: "ENERGY",
|
|
92222
|
+
water: "WATER"
|
|
92223
|
+
};
|
|
92224
|
+
var WIRE_TO_PANEL_DOMAIN = {
|
|
92225
|
+
ENERGY: "energy",
|
|
92226
|
+
WATER: "water"
|
|
92227
|
+
};
|
|
92228
|
+
var PANEL_TO_WIRE_CATEGORY = {
|
|
92229
|
+
lojas: "SPECIFIC",
|
|
92230
|
+
area_comum: "COMMON_AREA"
|
|
92231
|
+
};
|
|
92232
|
+
var WIRE_TO_PANEL_CATEGORY = {
|
|
92233
|
+
SPECIFIC: "lojas",
|
|
92234
|
+
COMMON_AREA: "area_comum"
|
|
92235
|
+
};
|
|
92236
|
+
function panelDomainToWire(d) {
|
|
92237
|
+
const w = PANEL_TO_WIRE_DOMAIN[d];
|
|
92238
|
+
if (!w) throw new Error(`Unknown panel domain: ${String(d)}`);
|
|
92239
|
+
return w;
|
|
92240
|
+
}
|
|
92241
|
+
function wireDomainToPanel(w) {
|
|
92242
|
+
const d = WIRE_TO_PANEL_DOMAIN[w];
|
|
92243
|
+
if (!d) throw new Error(`Unknown wire domain: ${String(w)}`);
|
|
92244
|
+
return d;
|
|
92245
|
+
}
|
|
92246
|
+
function panelCategoryToWire(c) {
|
|
92247
|
+
const w = PANEL_TO_WIRE_CATEGORY[c];
|
|
92248
|
+
if (!w) throw new Error(`Unknown panel category: ${String(c)}`);
|
|
92249
|
+
return w;
|
|
92250
|
+
}
|
|
92251
|
+
function wireCategoryToPanel(w) {
|
|
92252
|
+
const c = WIRE_TO_PANEL_CATEGORY[w];
|
|
92253
|
+
if (!c) throw new Error(`Unknown wire category: ${String(w)}`);
|
|
92254
|
+
return c;
|
|
92255
|
+
}
|
|
92256
|
+
function normalizePriceString(input) {
|
|
92257
|
+
if (typeof input.price === "string" && input.price.trim() !== "") {
|
|
92258
|
+
const s2 = input.price.trim();
|
|
92259
|
+
if (!(Number(s2) > 0)) throw new Error(`Price must be > 0 (got "${s2}").`);
|
|
92260
|
+
return s2;
|
|
92261
|
+
}
|
|
92262
|
+
const numeric = typeof input.price === "number" ? input.price : typeof input.pricePerKwh === "number" ? input.pricePerKwh : NaN;
|
|
92263
|
+
if (!Number.isFinite(numeric) || numeric <= 0) {
|
|
92264
|
+
throw new Error("A positive price (string) or legacy numeric pricePerKwh is required.");
|
|
92265
|
+
}
|
|
92266
|
+
let s = numeric.toFixed(6).replace(/0+$/, "");
|
|
92267
|
+
if (/\.\d?$/.test(s)) s = numeric.toFixed(2);
|
|
92268
|
+
return s;
|
|
92269
|
+
}
|
|
92270
|
+
function priceToNumber(price) {
|
|
92271
|
+
return Number(price);
|
|
92272
|
+
}
|
|
92273
|
+
function isLeapYear(year) {
|
|
92274
|
+
return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
|
|
92275
|
+
}
|
|
92276
|
+
var MONTH_DAYS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
92277
|
+
function daysInMonthYear(year, month) {
|
|
92278
|
+
if (month === 2 && isLeapYear(year)) return 29;
|
|
92279
|
+
return MONTH_DAYS[month - 1];
|
|
92280
|
+
}
|
|
92281
|
+
function pad23(n) {
|
|
92282
|
+
return String(n).padStart(2, "0");
|
|
92283
|
+
}
|
|
92284
|
+
function assertValidCivilDate(date) {
|
|
92285
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(date);
|
|
92286
|
+
if (!m) throw new Error(`Invalid date: ${date}`);
|
|
92287
|
+
const y = Number(m[1]);
|
|
92288
|
+
const mo = Number(m[2]);
|
|
92289
|
+
const d = Number(m[3]);
|
|
92290
|
+
if (mo < 1 || mo > 12) throw new Error(`Invalid month in date: ${date}`);
|
|
92291
|
+
if (d < 1 || d > daysInMonthYear(y, mo)) {
|
|
92292
|
+
throw new Error(`Invalid day for ${y}-${pad23(mo)} (leap=${isLeapYear(y)}): ${date}`);
|
|
92293
|
+
}
|
|
92294
|
+
}
|
|
92295
|
+
function* eachDate(start, end) {
|
|
92296
|
+
const [ys, ms, ds] = start.split("-").map(Number);
|
|
92297
|
+
const [ye, me, de] = end.split("-").map(Number);
|
|
92298
|
+
const t1 = Date.UTC(ye, me - 1, de);
|
|
92299
|
+
for (let t = Date.UTC(ys, ms - 1, ds); t <= t1; t += 864e5) {
|
|
92300
|
+
const dt = new Date(t);
|
|
92301
|
+
yield `${dt.getUTCFullYear()}-${pad23(dt.getUTCMonth() + 1)}-${pad23(dt.getUTCDate())}`;
|
|
92302
|
+
}
|
|
92303
|
+
}
|
|
92304
|
+
function normalizeBand(input) {
|
|
92305
|
+
const price = normalizePriceString(input);
|
|
92306
|
+
const band = {
|
|
92307
|
+
domain: input.domain,
|
|
92308
|
+
category: input.category,
|
|
92309
|
+
periodType: input.periodType,
|
|
92310
|
+
price
|
|
92311
|
+
};
|
|
92312
|
+
if (input.year != null) band.year = input.year;
|
|
92313
|
+
if (input.periodKey != null) band.periodKey = input.periodKey;
|
|
92314
|
+
if (input.start != null) band.start = input.start;
|
|
92315
|
+
if (input.end != null) band.end = input.end;
|
|
92316
|
+
if (input.date != null) band.date = input.date;
|
|
92317
|
+
if (input.startHour != null) band.startHour = input.startHour;
|
|
92318
|
+
if (input.endHour != null) band.endHour = input.endHour;
|
|
92319
|
+
return band;
|
|
92320
|
+
}
|
|
92321
|
+
function selectorKey(sel) {
|
|
92322
|
+
return `${sel.domain}|${sel.category}|${sel.year}`;
|
|
92323
|
+
}
|
|
92324
|
+
function bandSelector(band, customerId, year) {
|
|
92325
|
+
return {
|
|
92326
|
+
customerId,
|
|
92327
|
+
domain: panelDomainToWire(band.domain),
|
|
92328
|
+
category: panelCategoryToWire(band.category),
|
|
92329
|
+
year
|
|
92330
|
+
};
|
|
92331
|
+
}
|
|
92332
|
+
function panelEntryToBand(e) {
|
|
92333
|
+
const price = normalizePriceString({ price: e.price, pricePerKwh: e.pricePerKwh });
|
|
92334
|
+
if (e.periodType === "month") {
|
|
92335
|
+
if (!e.periodKey) throw new Error("month entry missing periodKey");
|
|
92336
|
+
return { domain: e.domain, category: e.category, periodType: "month", periodKey: e.periodKey, price };
|
|
92337
|
+
}
|
|
92338
|
+
if (!e.start || !e.end) throw new Error("range entry missing start/end");
|
|
92339
|
+
return { domain: e.domain, category: e.category, periodType: "range", start: e.start, end: e.end, price };
|
|
92340
|
+
}
|
|
92341
|
+
function bandToPanelEntry(band, customerId) {
|
|
92342
|
+
const base = {
|
|
92343
|
+
customerId,
|
|
92344
|
+
domain: band.domain,
|
|
92345
|
+
category: band.category,
|
|
92346
|
+
currency: "BRL",
|
|
92347
|
+
price: band.price,
|
|
92348
|
+
pricePerKwh: priceToNumber(band.price)
|
|
92349
|
+
};
|
|
92350
|
+
if (band.periodType === "month" && band.periodKey) {
|
|
92351
|
+
return { ...base, periodType: "month", periodKey: band.periodKey };
|
|
92352
|
+
}
|
|
92353
|
+
if (band.periodType === "year" && band.year != null) {
|
|
92354
|
+
return { ...base, periodType: "range", start: `${band.year}-01-01`, end: `${band.year}-12-31` };
|
|
92355
|
+
}
|
|
92356
|
+
if (band.periodType === "range" && band.start && band.end) {
|
|
92357
|
+
return { ...base, periodType: "range", start: band.start, end: band.end };
|
|
92358
|
+
}
|
|
92359
|
+
const date = band.date || band.start || "";
|
|
92360
|
+
return { ...base, periodType: "range", start: date, end: date };
|
|
92361
|
+
}
|
|
92362
|
+
function expandDayToHourBuckets(date, price) {
|
|
92363
|
+
assertValidCivilDate(date);
|
|
92364
|
+
const out = [];
|
|
92365
|
+
for (let h2 = 0; h2 < 24; h2++) out.push({ level: "HOUR", ref: `${date}T${pad23(h2)}`, price });
|
|
92366
|
+
return out;
|
|
92367
|
+
}
|
|
92368
|
+
function expandBandHours(date, startHour, endHour, price) {
|
|
92369
|
+
assertValidCivilDate(date);
|
|
92370
|
+
if (startHour < 0 || endHour > 23 || startHour > endHour) {
|
|
92371
|
+
throw new Error(`Invalid hour band ${startHour}-${endHour} for ${date}`);
|
|
92372
|
+
}
|
|
92373
|
+
const out = [];
|
|
92374
|
+
for (let h2 = startHour; h2 <= endHour; h2++) out.push({ level: "HOUR", ref: `${date}T${pad23(h2)}`, price });
|
|
92375
|
+
return out;
|
|
92376
|
+
}
|
|
92377
|
+
function bandDateBounds(band) {
|
|
92378
|
+
switch (band.periodType) {
|
|
92379
|
+
case "month": {
|
|
92380
|
+
if (!band.periodKey) throw new Error("month band missing periodKey");
|
|
92381
|
+
const [y, m] = band.periodKey.split("-").map(Number);
|
|
92382
|
+
return { start: `${band.periodKey}-01`, end: `${band.periodKey}-${pad23(daysInMonthYear(y, m))}` };
|
|
92383
|
+
}
|
|
92384
|
+
case "range": {
|
|
92385
|
+
if (!band.start || !band.end) throw new Error("range band missing start/end");
|
|
92386
|
+
return { start: band.start, end: band.end };
|
|
92387
|
+
}
|
|
92388
|
+
case "day":
|
|
92389
|
+
case "band": {
|
|
92390
|
+
const d = band.date || band.start;
|
|
92391
|
+
if (!d) throw new Error("day/band missing date");
|
|
92392
|
+
return { start: d, end: d };
|
|
92393
|
+
}
|
|
92394
|
+
case "year": {
|
|
92395
|
+
const y = band.year;
|
|
92396
|
+
if (y == null) throw new Error("year band missing year");
|
|
92397
|
+
return { start: `${y}-01-01`, end: `${y}-12-31` };
|
|
92398
|
+
}
|
|
92399
|
+
default:
|
|
92400
|
+
throw new Error(`Unsupported band periodType: ${String(band.periodType)}`);
|
|
92401
|
+
}
|
|
92402
|
+
}
|
|
92403
|
+
function expandBandToHourBucketsByYear(band) {
|
|
92404
|
+
const byYear = /* @__PURE__ */ new Map();
|
|
92405
|
+
const push = (year, buckets) => {
|
|
92406
|
+
const arr = byYear.get(year) || [];
|
|
92407
|
+
arr.push(...buckets);
|
|
92408
|
+
byYear.set(year, arr);
|
|
92409
|
+
};
|
|
92410
|
+
if (band.periodType === "band") {
|
|
92411
|
+
const date = band.date || band.start;
|
|
92412
|
+
push(Number(date.slice(0, 4)), expandBandHours(date, band.startHour ?? 0, band.endHour ?? 23, band.price));
|
|
92413
|
+
return byYear;
|
|
92414
|
+
}
|
|
92415
|
+
const { start, end } = bandDateBounds(band);
|
|
92416
|
+
for (const date of eachDate(start, end)) {
|
|
92417
|
+
push(Number(date.slice(0, 4)), expandDayToHourBuckets(date, band.price));
|
|
92418
|
+
}
|
|
92419
|
+
return byYear;
|
|
92420
|
+
}
|
|
92421
|
+
function collapseHoursToBands(date, hours, dims) {
|
|
92422
|
+
const sorted = [...hours].sort((a, b) => a.hour - b.hour);
|
|
92423
|
+
const runs = [];
|
|
92424
|
+
for (const h2 of sorted) {
|
|
92425
|
+
const cur = runs[runs.length - 1];
|
|
92426
|
+
if (cur && h2.hour === cur.endHour + 1 && h2.price === cur.price) {
|
|
92427
|
+
cur.endHour = h2.hour;
|
|
92428
|
+
} else {
|
|
92429
|
+
runs.push({ startHour: h2.hour, endHour: h2.hour, price: h2.price });
|
|
92430
|
+
}
|
|
92431
|
+
}
|
|
92432
|
+
return runs.map(
|
|
92433
|
+
(r) => r.startHour === 0 && r.endHour === 23 ? { domain: dims.domain, category: dims.category, periodType: "day", date, price: r.price } : {
|
|
92434
|
+
domain: dims.domain,
|
|
92435
|
+
category: dims.category,
|
|
92436
|
+
periodType: "band",
|
|
92437
|
+
date,
|
|
92438
|
+
startHour: r.startHour,
|
|
92439
|
+
endHour: r.endHour,
|
|
92440
|
+
price: r.price
|
|
92441
|
+
}
|
|
92442
|
+
);
|
|
92443
|
+
}
|
|
92444
|
+
function dayNodeToHours(node) {
|
|
92445
|
+
const dayPrice = typeof node.price === "string" ? node.price : void 0;
|
|
92446
|
+
const hourly = node.hourly || {};
|
|
92447
|
+
const hourKeys = Object.keys(hourly);
|
|
92448
|
+
if (hourKeys.length === 0) {
|
|
92449
|
+
return dayPrice != null ? Array.from({ length: 24 }, (_, h2) => ({ hour: h2, price: dayPrice })) : null;
|
|
92450
|
+
}
|
|
92451
|
+
const out = [];
|
|
92452
|
+
for (let h2 = 0; h2 < 24; h2++) {
|
|
92453
|
+
const ov = hourly[String(h2)];
|
|
92454
|
+
const price = ov && typeof ov.price === "string" ? ov.price : dayPrice;
|
|
92455
|
+
if (price != null) out.push({ hour: h2, price });
|
|
92456
|
+
}
|
|
92457
|
+
return out.length ? out : null;
|
|
92458
|
+
}
|
|
92459
|
+
function normalizeDayKey(key, monthKey) {
|
|
92460
|
+
if (/^\d{2}-\d{2}$/.test(key)) return key;
|
|
92461
|
+
if (/^\d{2}$/.test(key) && monthKey) return `${monthKey}-${key}`;
|
|
92462
|
+
return key;
|
|
92463
|
+
}
|
|
92464
|
+
function mergeContiguousDays(days, year) {
|
|
92465
|
+
const simple = days.every((d) => d.periodType === "day" && d.date);
|
|
92466
|
+
if (!simple || days.length === 0) return days;
|
|
92467
|
+
const sorted = [...days].sort((a, b) => a.date < b.date ? -1 : 1);
|
|
92468
|
+
const out = [];
|
|
92469
|
+
let run = null;
|
|
92470
|
+
const flush = () => {
|
|
92471
|
+
if (!run) return;
|
|
92472
|
+
out.push(
|
|
92473
|
+
run.start === run.end ? { domain: run.dims.domain, category: run.dims.category, periodType: "day", date: run.start, price: run.price } : {
|
|
92474
|
+
domain: run.dims.domain,
|
|
92475
|
+
category: run.dims.category,
|
|
92476
|
+
periodType: "range",
|
|
92477
|
+
start: run.start,
|
|
92478
|
+
end: run.end,
|
|
92479
|
+
price: run.price
|
|
92480
|
+
}
|
|
92481
|
+
);
|
|
92482
|
+
run = null;
|
|
92483
|
+
};
|
|
92484
|
+
for (const d of sorted) {
|
|
92485
|
+
if (run && d.price === run.price && isNextDay(run.end, d.date)) {
|
|
92486
|
+
run.end = d.date;
|
|
92487
|
+
} else {
|
|
92488
|
+
flush();
|
|
92489
|
+
run = { start: d.date, end: d.date, price: d.price, dims: d };
|
|
92490
|
+
}
|
|
92491
|
+
}
|
|
92492
|
+
flush();
|
|
92493
|
+
void year;
|
|
92494
|
+
return out;
|
|
92495
|
+
}
|
|
92496
|
+
function isNextDay(prev, next) {
|
|
92497
|
+
const [py, pm, pd] = prev.split("-").map(Number);
|
|
92498
|
+
const [ny, nm, nd] = next.split("-").map(Number);
|
|
92499
|
+
return Date.UTC(py, pm - 1, pd) + 864e5 === Date.UTC(ny, nm - 1, nd);
|
|
92500
|
+
}
|
|
92501
|
+
function collapseTreeToBands(tree, dims) {
|
|
92502
|
+
if (!tree || typeof tree !== "object") return [];
|
|
92503
|
+
const dimOnly = { domain: dims.domain, category: dims.category };
|
|
92504
|
+
if (tree.annual && typeof tree.annual.price === "string" && !tree.daily && !tree.monthly) {
|
|
92505
|
+
return [{ ...dimOnly, periodType: "year", year: dims.year, price: tree.annual.price }];
|
|
92506
|
+
}
|
|
92507
|
+
const dayBands = [];
|
|
92508
|
+
const collectDaily = (daily, monthKey) => {
|
|
92509
|
+
for (const rawKey of Object.keys(daily)) {
|
|
92510
|
+
const mmdd = normalizeDayKey(rawKey, monthKey);
|
|
92511
|
+
const date = `${dims.year}-${mmdd}`;
|
|
92512
|
+
const hours = dayNodeToHours(daily[rawKey]);
|
|
92513
|
+
if (!hours) continue;
|
|
92514
|
+
dayBands.push(...collapseHoursToBands(date, hours, dimOnly));
|
|
92515
|
+
}
|
|
92516
|
+
};
|
|
92517
|
+
if (tree.daily) collectDaily(tree.daily);
|
|
92518
|
+
if (tree.monthly) {
|
|
92519
|
+
for (const mm of Object.keys(tree.monthly)) {
|
|
92520
|
+
const node = tree.monthly[mm];
|
|
92521
|
+
if (node.daily) {
|
|
92522
|
+
collectDaily(node.daily, mm);
|
|
92523
|
+
} else if (typeof node.price === "string") {
|
|
92524
|
+
const last = daysInMonthYear(dims.year, Number(mm));
|
|
92525
|
+
for (let d = 1; d <= last; d++) {
|
|
92526
|
+
dayBands.push({ ...dimOnly, periodType: "day", date: `${dims.year}-${mm}-${pad23(d)}`, price: node.price });
|
|
92527
|
+
}
|
|
92528
|
+
}
|
|
92529
|
+
}
|
|
92530
|
+
}
|
|
92531
|
+
return mergeContiguousDays(dayBands, dims.year);
|
|
92532
|
+
}
|
|
92533
|
+
var WIRE_COMBOS = [
|
|
92534
|
+
["ENERGY", "SPECIFIC"],
|
|
92535
|
+
["ENERGY", "COMMON_AREA"],
|
|
92536
|
+
["WATER", "SPECIFIC"],
|
|
92537
|
+
["WATER", "COMMON_AREA"]
|
|
92538
|
+
];
|
|
92539
|
+
var TariffApiAdapter = class {
|
|
92540
|
+
client;
|
|
92541
|
+
year;
|
|
92542
|
+
/** Last-seen version per `(domain|category|year)` for optimistic concurrency. */
|
|
92543
|
+
versions = /* @__PURE__ */ new Map();
|
|
92544
|
+
constructor(client, opts = {}) {
|
|
92545
|
+
this.client = client;
|
|
92546
|
+
this.year = opts.year ?? (/* @__PURE__ */ new Date()).getFullYear();
|
|
92547
|
+
}
|
|
92548
|
+
/** Default load year. */
|
|
92549
|
+
getYear() {
|
|
92550
|
+
return this.year;
|
|
92551
|
+
}
|
|
92552
|
+
/**
|
|
92553
|
+
* Load every `(domain × category)` tariff for a customer and collapse each into
|
|
92554
|
+
* panel entries. An empty tariff (`version: 0`) contributes no entries — it is
|
|
92555
|
+
* "no entries", never an error. Read errors propagate (caller surfaces them).
|
|
92556
|
+
*/
|
|
92557
|
+
async loadEntriesForCustomer(customerId, year = this.year) {
|
|
92558
|
+
const out = [];
|
|
92559
|
+
for (const [domain, category] of WIRE_COMBOS) {
|
|
92560
|
+
const sel = { customerId, domain, category, year };
|
|
92561
|
+
const resp = await this.client.getTariff(sel, "hour");
|
|
92562
|
+
this.versions.set(selectorKey(sel), resp.version);
|
|
92563
|
+
if (resp.version === 0) continue;
|
|
92564
|
+
const bands = collapseTreeToBands(resp.tree, {
|
|
92565
|
+
year,
|
|
92566
|
+
domain: wireDomainToPanel(domain),
|
|
92567
|
+
category: wireCategoryToPanel(category)
|
|
92568
|
+
});
|
|
92569
|
+
for (const b of bands) out.push(bandToPanelEntry(b, customerId));
|
|
92570
|
+
}
|
|
92571
|
+
return out;
|
|
92572
|
+
}
|
|
92573
|
+
/** Convenience: read + collapse one specific tariff. */
|
|
92574
|
+
async loadBands(customerId, domain, category, year = this.year) {
|
|
92575
|
+
const sel = { customerId, domain: panelDomainToWire(domain), category: panelCategoryToWire(category), year };
|
|
92576
|
+
const resp = await this.client.getTariff(sel, "hour");
|
|
92577
|
+
this.versions.set(selectorKey(sel), resp.version);
|
|
92578
|
+
const bands = resp.version === 0 ? [] : collapseTreeToBands(resp.tree, { year, domain, category });
|
|
92579
|
+
return { bands, version: resp.version };
|
|
92580
|
+
}
|
|
92581
|
+
/**
|
|
92582
|
+
* Persist one panel edit. Annual bands REPLACE the year (PUT); every other
|
|
92583
|
+
* period MERGES its hourly buckets (PATCH), so sibling periods survive. A range
|
|
92584
|
+
* spanning a year boundary writes once per year. `expectedVersion` is carried
|
|
92585
|
+
* from the last-seen version; a stale guard throws `TARIFF_VERSION_CONFLICT`
|
|
92586
|
+
* (surfaced, never swallowed).
|
|
92587
|
+
*/
|
|
92588
|
+
async saveEntry(customerId, entryOrBand) {
|
|
92589
|
+
const band = toBand(entryOrBand);
|
|
92590
|
+
if (band.periodType === "year") {
|
|
92591
|
+
const year = band.year ?? this.year;
|
|
92592
|
+
const sel = bandSelector(band, customerId, year);
|
|
92593
|
+
const key = selectorKey(sel);
|
|
92594
|
+
const res = await this.client.putTariff(sel, { annual: { price: band.price } }, this.versions.get(key));
|
|
92595
|
+
this.versions.set(key, res.version);
|
|
92596
|
+
return;
|
|
92597
|
+
}
|
|
92598
|
+
const byYear = expandBandToHourBucketsByYear(band);
|
|
92599
|
+
for (const [year, buckets] of byYear) {
|
|
92600
|
+
const sel = bandSelector(band, customerId, year);
|
|
92601
|
+
const key = selectorKey(sel);
|
|
92602
|
+
const res = await this.client.patchTariff(sel, buckets, this.versions.get(key));
|
|
92603
|
+
this.versions.set(key, res.version);
|
|
92604
|
+
}
|
|
92605
|
+
}
|
|
92606
|
+
/**
|
|
92607
|
+
* Remove a panel period. The contract offers whole-year DELETE or a single
|
|
92608
|
+
* sub-bucket per call, so a partial period is deleted day-by-day (`level:'DAY'`).
|
|
92609
|
+
* Removing a full year deletes the whole year in one call.
|
|
92610
|
+
*/
|
|
92611
|
+
async deleteEntry(customerId, entryOrBand) {
|
|
92612
|
+
const band = toBand(entryOrBand);
|
|
92613
|
+
if (band.periodType === "year") {
|
|
92614
|
+
const year = band.year ?? this.year;
|
|
92615
|
+
const sel = bandSelector(band, customerId, year);
|
|
92616
|
+
const key = selectorKey(sel);
|
|
92617
|
+
const res = await this.client.deleteTariff(sel, { expectedVersion: this.versions.get(key) });
|
|
92618
|
+
if (typeof res.version === "number") this.versions.set(key, res.version);
|
|
92619
|
+
return;
|
|
92620
|
+
}
|
|
92621
|
+
const { start, end } = bandDateBounds(band);
|
|
92622
|
+
for (const date of eachDate(start, end)) {
|
|
92623
|
+
const year = Number(date.slice(0, 4));
|
|
92624
|
+
const sel = bandSelector(band, customerId, year);
|
|
92625
|
+
const key = selectorKey(sel);
|
|
92626
|
+
const res = await this.client.deleteTariff(sel, {
|
|
92627
|
+
bucket: { level: "DAY", ref: date },
|
|
92628
|
+
expectedVersion: this.versions.get(key)
|
|
92629
|
+
});
|
|
92630
|
+
if (typeof res.version === "number") this.versions.set(key, res.version);
|
|
92631
|
+
}
|
|
92632
|
+
}
|
|
92633
|
+
/** Seed the version cache from an out-of-band read (e.g. a raw client call). */
|
|
92634
|
+
rememberVersion(resp) {
|
|
92635
|
+
this.versions.set(`${resp.domain}|${resp.category}|${resp.year}`, resp.version);
|
|
92636
|
+
}
|
|
92637
|
+
};
|
|
92638
|
+
function toBand(entryOrBand) {
|
|
92639
|
+
if ("periodType" in entryOrBand && (entryOrBand.periodType === "month" || entryOrBand.periodType === "range") && !("startHour" in entryOrBand)) {
|
|
92640
|
+
if ("customerId" in entryOrBand) return panelEntryToBand(entryOrBand);
|
|
92641
|
+
}
|
|
92642
|
+
return normalizeBand(entryOrBand);
|
|
92643
|
+
}
|
|
92644
|
+
function createTariffApiAdapter(client, opts) {
|
|
92645
|
+
return new TariffApiAdapter(client, opts);
|
|
92646
|
+
}
|
|
92647
|
+
|
|
91149
92648
|
// src/components/pricing-panel/openPricingPanel.ts
|
|
91150
92649
|
var MODAL_ID2 = "myio-pricing-panel";
|
|
91151
92650
|
function escapeHtml8(value) {
|
|
@@ -91226,8 +92725,20 @@ function openPricingPanel(params) {
|
|
|
91226
92725
|
doc.getElementById(MODAL_ID2)?.remove();
|
|
91227
92726
|
const allowed = isPricingAllowed(params.currentUserEmail, isSuperAdmin());
|
|
91228
92727
|
const customers = params.customers || [];
|
|
91229
|
-
|
|
91230
|
-
let
|
|
92728
|
+
const tariffApi = params.tariffApi;
|
|
92729
|
+
let adapter = null;
|
|
92730
|
+
if (allowed && tariffApi) {
|
|
92731
|
+
const client = new TariffApiClient({
|
|
92732
|
+
baseUrl: tariffApi.baseUrl,
|
|
92733
|
+
apiKey: tariffApi.apiKey,
|
|
92734
|
+
jwt: tariffApi.jwt,
|
|
92735
|
+
tenantId: tariffApi.tenantId,
|
|
92736
|
+
fetchImpl: tariffApi.fetchImpl
|
|
92737
|
+
});
|
|
92738
|
+
adapter = new TariffApiAdapter(client, { year: tariffApi.year });
|
|
92739
|
+
}
|
|
92740
|
+
let entries = allowed ? adapter ? (params.initialEntries || []).map((e) => ({ ...e })) : mergeEntries(loadJson(doc, keyEntries, []), params.initialEntries || [], author) : [];
|
|
92741
|
+
let auditLog = allowed && !adapter ? loadJson(doc, keyAudit, []) : [];
|
|
91231
92742
|
const modal = doc.createElement("div");
|
|
91232
92743
|
modal.id = MODAL_ID2;
|
|
91233
92744
|
modal.className = "myio-pricing";
|
|
@@ -91457,9 +92968,47 @@ function openPricingPanel(params) {
|
|
|
91457
92968
|
renderList2();
|
|
91458
92969
|
})
|
|
91459
92970
|
);
|
|
92971
|
+
if (adapter) {
|
|
92972
|
+
customerSel.addEventListener("change", () => {
|
|
92973
|
+
void loadFromApi();
|
|
92974
|
+
});
|
|
92975
|
+
}
|
|
91460
92976
|
syncPeriodFields();
|
|
91461
92977
|
syncUnit();
|
|
91462
|
-
|
|
92978
|
+
function surfaceApiError(err) {
|
|
92979
|
+
const code = err?.code;
|
|
92980
|
+
if (code === "TARIFF_VERSION_CONFLICT") {
|
|
92981
|
+
const cv = err.currentVersion;
|
|
92982
|
+
showError(
|
|
92983
|
+
`Conflito de vers\xE3o: a tarifa mudou no servidor${cv != null ? ` (vers\xE3o atual ${cv})` : ""}. Reabra o painel e tente novamente.`
|
|
92984
|
+
);
|
|
92985
|
+
return;
|
|
92986
|
+
}
|
|
92987
|
+
showError(`Falha ao salvar a tarifa no servidor${code ? ` (${code})` : ""}.`);
|
|
92988
|
+
}
|
|
92989
|
+
async function loadFromApi() {
|
|
92990
|
+
if (!adapter) return;
|
|
92991
|
+
const customerId = customerSel.value;
|
|
92992
|
+
if (!customerId) return;
|
|
92993
|
+
try {
|
|
92994
|
+
const loaded = await adapter.loadEntriesForCustomer(customerId);
|
|
92995
|
+
entries = entries.filter((e) => e.customerId !== customerId).concat(loaded);
|
|
92996
|
+
renderList2();
|
|
92997
|
+
} catch (err) {
|
|
92998
|
+
surfaceApiError(err);
|
|
92999
|
+
}
|
|
93000
|
+
}
|
|
93001
|
+
const persist = (changed) => {
|
|
93002
|
+
if (adapter) {
|
|
93003
|
+
if (changed?.kind === "upsert") {
|
|
93004
|
+
adapter.saveEntry(changed.entry.customerId, changed.entry).catch(surfaceApiError);
|
|
93005
|
+
} else if (changed?.kind === "remove") {
|
|
93006
|
+
adapter.deleteEntry(changed.entry.customerId, changed.entry).catch(surfaceApiError);
|
|
93007
|
+
}
|
|
93008
|
+
if (typeof params.onSave === "function") params.onSave(entries.map((e) => ({ ...e })));
|
|
93009
|
+
emit("save", entries.map((e) => ({ ...e })));
|
|
93010
|
+
return;
|
|
93011
|
+
}
|
|
91463
93012
|
saveJson(doc, keyEntries, entries);
|
|
91464
93013
|
saveJson(doc, keyAudit, auditLog);
|
|
91465
93014
|
if (typeof params.onSave === "function") params.onSave(entries.map((e) => ({ ...e })));
|
|
@@ -91486,7 +93035,7 @@ function openPricingPanel(params) {
|
|
|
91486
93035
|
<span class="myio-pricing__item-period">${badge(e.domain, e.category)} ${escapeHtml8(
|
|
91487
93036
|
formatPeriodLabel(e)
|
|
91488
93037
|
)}</span>
|
|
91489
|
-
<span class="myio-pricing__item-price">${escapeHtml8(
|
|
93038
|
+
<span class="myio-pricing__item-price">${escapeHtml8(formatBRL2(e.pricePerKwh))} ${escapeHtml8(
|
|
91490
93039
|
unitLabel(e.domain)
|
|
91491
93040
|
)}</span>
|
|
91492
93041
|
<button class="myio-pricing__remove" data-remove="${escapeHtml8(e.domain)}|${escapeHtml8(
|
|
@@ -91498,6 +93047,11 @@ function openPricingPanel(params) {
|
|
|
91498
93047
|
listEl.querySelectorAll("[data-remove]").forEach((btn) => {
|
|
91499
93048
|
btn.addEventListener("click", () => {
|
|
91500
93049
|
const [domain, category, boundsKey] = String(btn.getAttribute("data-remove")).split("|");
|
|
93050
|
+
const removedEntry = entries.find((e) => {
|
|
93051
|
+
if (e.customerId !== customerId || e.domain !== domain || e.category !== category) return false;
|
|
93052
|
+
const b = entryBounds(e);
|
|
93053
|
+
return Boolean(b && `${b.start}__${b.end}` === boundsKey);
|
|
93054
|
+
});
|
|
91501
93055
|
const result = removeEntryByBounds(
|
|
91502
93056
|
entries,
|
|
91503
93057
|
{
|
|
@@ -91510,7 +93064,7 @@ function openPricingPanel(params) {
|
|
|
91510
93064
|
);
|
|
91511
93065
|
entries = result.entries;
|
|
91512
93066
|
pushAudit(result.audit);
|
|
91513
|
-
persist();
|
|
93067
|
+
persist(removedEntry ? { kind: "remove", entry: removedEntry } : void 0);
|
|
91514
93068
|
renderList2();
|
|
91515
93069
|
emit("remove", result.audit);
|
|
91516
93070
|
});
|
|
@@ -91553,7 +93107,7 @@ function openPricingPanel(params) {
|
|
|
91553
93107
|
}
|
|
91554
93108
|
entries = result.entries;
|
|
91555
93109
|
pushAudit(result.audit);
|
|
91556
|
-
persist();
|
|
93110
|
+
persist({ kind: "upsert", entry: candidate });
|
|
91557
93111
|
customerSel.value = candidate.customerId;
|
|
91558
93112
|
domainSel.value = candidate.domain;
|
|
91559
93113
|
categorySel.value = candidate.category;
|
|
@@ -91569,11 +93123,11 @@ function openPricingPanel(params) {
|
|
|
91569
93123
|
{ value: String(kpis.periodsByDomain.energy), label: "Per\xEDodos \xB7 Energia" },
|
|
91570
93124
|
{ value: String(kpis.periodsByDomain.water), label: "Per\xEDodos \xB7 \xC1gua" },
|
|
91571
93125
|
{
|
|
91572
|
-
value: kpis.avgEnergyPrice != null ? `${
|
|
93126
|
+
value: kpis.avgEnergyPrice != null ? `${formatBRL2(kpis.avgEnergyPrice)}` : "\u2014",
|
|
91573
93127
|
label: "Pre\xE7o m\xE9dio R$/kWh"
|
|
91574
93128
|
},
|
|
91575
93129
|
{
|
|
91576
|
-
value: kpis.avgWaterPrice != null ? `${
|
|
93130
|
+
value: kpis.avgWaterPrice != null ? `${formatBRL2(kpis.avgWaterPrice)}` : "\u2014",
|
|
91577
93131
|
label: "Pre\xE7o m\xE9dio R$/m\xB3"
|
|
91578
93132
|
},
|
|
91579
93133
|
{
|
|
@@ -91609,13 +93163,13 @@ function openPricingPanel(params) {
|
|
|
91609
93163
|
<td>${escapeHtml8(DOMAIN_LABEL[e.domain])}</td>
|
|
91610
93164
|
<td>${escapeHtml8(CATEGORY_LABEL[e.category])}</td>
|
|
91611
93165
|
<td>${escapeHtml8(formatPeriodLabel(e))}</td>
|
|
91612
|
-
<td>${escapeHtml8(
|
|
93166
|
+
<td>${escapeHtml8(formatBRL2(e.pricePerKwh))} ${escapeHtml8(unitLabel(e.domain))}</td>
|
|
91613
93167
|
</tr>`
|
|
91614
93168
|
).join("") : `<tr><td colspan="5" style="text-align:center;color:var(--myio-text-muted,#6b7280);padding:24px;">Nenhum pre\xE7o para o filtro selecionado.</td></tr>`;
|
|
91615
93169
|
}
|
|
91616
93170
|
function renderHistory() {
|
|
91617
93171
|
historyList.innerHTML = auditLog.map((rec) => {
|
|
91618
|
-
const priceInfo = rec.action === "price-changed" ? ` \u2014 ${
|
|
93172
|
+
const priceInfo = rec.action === "price-changed" ? ` \u2014 ${formatBRL2(rec.before?.pricePerKwh ?? NaN)} \u2192 ${formatBRL2(rec.after?.pricePerKwh ?? NaN)}` : rec.after?.pricePerKwh != null ? ` \u2014 ${formatBRL2(rec.after.pricePerKwh)}` : rec.before?.pricePerKwh != null ? ` \u2014 ${formatBRL2(rec.before.pricePerKwh)}` : "";
|
|
91619
93173
|
return `
|
|
91620
93174
|
<li class="myio-pricing__history-item">
|
|
91621
93175
|
<div class="myio-pricing__history-head">
|
|
@@ -91633,9 +93187,1062 @@ function openPricingPanel(params) {
|
|
|
91633
93187
|
historyEmpty.style.display = auditLog.length ? "none" : "";
|
|
91634
93188
|
}
|
|
91635
93189
|
renderList2();
|
|
93190
|
+
if (adapter) void loadFromApi();
|
|
91636
93191
|
return handle;
|
|
91637
93192
|
}
|
|
91638
93193
|
|
|
93194
|
+
// src/components/financial-goals/goalsMoneyClient.ts
|
|
93195
|
+
var GoalsMoneyApiError = class extends Error {
|
|
93196
|
+
code;
|
|
93197
|
+
status;
|
|
93198
|
+
details;
|
|
93199
|
+
currentVersion;
|
|
93200
|
+
constructor(code, status, message, details) {
|
|
93201
|
+
super(message || code);
|
|
93202
|
+
this.name = "GoalsMoneyApiError";
|
|
93203
|
+
this.code = code;
|
|
93204
|
+
this.status = status;
|
|
93205
|
+
this.details = details;
|
|
93206
|
+
const cv = details && details.currentVersion;
|
|
93207
|
+
this.currentVersion = typeof cv === "number" ? cv : void 0;
|
|
93208
|
+
}
|
|
93209
|
+
};
|
|
93210
|
+
function joinUrl2(baseUrl, basePath, path) {
|
|
93211
|
+
const b = baseUrl.replace(/\/+$/, "");
|
|
93212
|
+
const bp = basePath ? `/${basePath.replace(/^\/+|\/+$/g, "")}` : "";
|
|
93213
|
+
const p = path.startsWith("/") ? path : `/${path}`;
|
|
93214
|
+
return `${b}${bp}${p}`;
|
|
93215
|
+
}
|
|
93216
|
+
function parseETagVersion2(headers) {
|
|
93217
|
+
const raw = headers.get("ETag") || headers.get("etag");
|
|
93218
|
+
if (!raw) return void 0;
|
|
93219
|
+
const m = /"?(-?\d+)"?/.exec(raw);
|
|
93220
|
+
return m ? Number(m[1]) : void 0;
|
|
93221
|
+
}
|
|
93222
|
+
function guardBody2(expectedVersion) {
|
|
93223
|
+
return typeof expectedVersion === "number" ? { expectedVersion } : {};
|
|
93224
|
+
}
|
|
93225
|
+
var GoalsMoneyClient = class {
|
|
93226
|
+
cfg;
|
|
93227
|
+
fetchImpl;
|
|
93228
|
+
basePath;
|
|
93229
|
+
constructor(config2) {
|
|
93230
|
+
if (!config2 || !config2.baseUrl) {
|
|
93231
|
+
throw new Error("GoalsMoneyClient requires a baseUrl.");
|
|
93232
|
+
}
|
|
93233
|
+
this.cfg = config2;
|
|
93234
|
+
const injected = config2.fetchImpl || globalThis.fetch;
|
|
93235
|
+
if (typeof injected !== "function") {
|
|
93236
|
+
throw new Error("GoalsMoneyClient requires a fetch implementation.");
|
|
93237
|
+
}
|
|
93238
|
+
this.fetchImpl = config2.fetchImpl ? config2.fetchImpl : injected.bind(globalThis);
|
|
93239
|
+
this.basePath = config2.basePath ?? "api/v1";
|
|
93240
|
+
}
|
|
93241
|
+
authHeaders() {
|
|
93242
|
+
const h2 = {};
|
|
93243
|
+
if (this.cfg.apiKey) h2["X-API-Key"] = this.cfg.apiKey;
|
|
93244
|
+
if (this.cfg.jwt) h2["Authorization"] = `Bearer ${this.cfg.jwt}`;
|
|
93245
|
+
if (this.cfg.tenantId) h2["X-Tenant-Id"] = this.cfg.tenantId;
|
|
93246
|
+
return h2;
|
|
93247
|
+
}
|
|
93248
|
+
goalsPath(sel) {
|
|
93249
|
+
return `/customers/${encodeURIComponent(sel.customerId)}/goals`;
|
|
93250
|
+
}
|
|
93251
|
+
/**
|
|
93252
|
+
* Read a quantity goal **in money** (`?withMoney=true`). Returns the quantity
|
|
93253
|
+
* tree (values are quantities, `monetaryValue`s are decimal strings), plus the
|
|
93254
|
+
* normalized money overlay (`available` | `unavailable`) and, when a CURRENCY
|
|
93255
|
+
* goal exists, the folded budget verdict. Coverage states are NOT thrown.
|
|
93256
|
+
*/
|
|
93257
|
+
async getGoalWithMoney(args) {
|
|
93258
|
+
const qs = new URLSearchParams();
|
|
93259
|
+
qs.set("domain", args.domain);
|
|
93260
|
+
qs.set("year", String(args.year));
|
|
93261
|
+
if (args.granularity) qs.set("granularity", args.granularity);
|
|
93262
|
+
qs.set("withMoney", "true");
|
|
93263
|
+
const url = joinUrl2(this.cfg.baseUrl, this.basePath, `${this.goalsPath(args)}?${qs.toString()}`);
|
|
93264
|
+
const res = await this.fetchImpl(url, {
|
|
93265
|
+
method: "GET",
|
|
93266
|
+
headers: { Accept: "application/json", ...this.authHeaders() }
|
|
93267
|
+
});
|
|
93268
|
+
const body = await this.readBody(res);
|
|
93269
|
+
if (!res.ok) throw this.toError(res, body);
|
|
93270
|
+
const etagVersion = parseETagVersion2(res.headers);
|
|
93271
|
+
const parsed = body || {};
|
|
93272
|
+
const version2 = typeof parsed.version === "number" ? parsed.version : etagVersion ?? 0;
|
|
93273
|
+
const measure = parsed.measure === "CURRENCY" ? "CURRENCY" : "QUANTITY";
|
|
93274
|
+
return {
|
|
93275
|
+
customerId: args.customerId,
|
|
93276
|
+
domain: args.domain,
|
|
93277
|
+
year: args.year,
|
|
93278
|
+
measure,
|
|
93279
|
+
version: version2,
|
|
93280
|
+
goal: {
|
|
93281
|
+
domain: args.domain,
|
|
93282
|
+
unit: typeof parsed.unit === "string" ? parsed.unit : "",
|
|
93283
|
+
// Tree is passed through verbatim — amounts/monetaryValues stay strings.
|
|
93284
|
+
tree: parsed.tree || {},
|
|
93285
|
+
version: version2
|
|
93286
|
+
},
|
|
93287
|
+
money: normalizeMoneyBlock(parsed.money, parsed.budget)
|
|
93288
|
+
};
|
|
93289
|
+
}
|
|
93290
|
+
/** Read the native CURRENCY budget goal (R$ target tree). */
|
|
93291
|
+
async getBudget(sel) {
|
|
93292
|
+
const qs = new URLSearchParams();
|
|
93293
|
+
qs.set("domain", sel.domain);
|
|
93294
|
+
qs.set("year", String(sel.year));
|
|
93295
|
+
qs.set("measure", "CURRENCY");
|
|
93296
|
+
const url = joinUrl2(this.cfg.baseUrl, this.basePath, `${this.goalsPath(sel)}?${qs.toString()}`);
|
|
93297
|
+
const res = await this.fetchImpl(url, {
|
|
93298
|
+
method: "GET",
|
|
93299
|
+
headers: { Accept: "application/json", ...this.authHeaders() }
|
|
93300
|
+
});
|
|
93301
|
+
const body = await this.readBody(res);
|
|
93302
|
+
if (!res.ok) throw this.toError(res, body);
|
|
93303
|
+
const etagVersion = parseETagVersion2(res.headers);
|
|
93304
|
+
const parsed = body || {};
|
|
93305
|
+
return {
|
|
93306
|
+
customerId: sel.customerId,
|
|
93307
|
+
domain: sel.domain,
|
|
93308
|
+
year: sel.year,
|
|
93309
|
+
measure: "CURRENCY",
|
|
93310
|
+
currency: parsed.currency,
|
|
93311
|
+
version: typeof parsed.version === "number" ? parsed.version : etagVersion ?? 0,
|
|
93312
|
+
tree: parsed.tree || {}
|
|
93313
|
+
};
|
|
93314
|
+
}
|
|
93315
|
+
/**
|
|
93316
|
+
* Set the native CURRENCY budget (PUT replace). The `tree` is sent **verbatim**
|
|
93317
|
+
* (`{ annual: { value: "120000.00" } }` or `{ monthly: {…} }`) — the client
|
|
93318
|
+
* does not coerce amounts, keeping the decimal-string contract end to end.
|
|
93319
|
+
* The optimistic guard rides both `If-Match` and body `expectedVersion`.
|
|
93320
|
+
*/
|
|
93321
|
+
async putBudget(args) {
|
|
93322
|
+
const qs = new URLSearchParams();
|
|
93323
|
+
qs.set("domain", args.domain);
|
|
93324
|
+
qs.set("year", String(args.year));
|
|
93325
|
+
qs.set("measure", "CURRENCY");
|
|
93326
|
+
const url = joinUrl2(this.cfg.baseUrl, this.basePath, `${this.goalsPath(args)}?${qs.toString()}`);
|
|
93327
|
+
const headers = {
|
|
93328
|
+
Accept: "application/json",
|
|
93329
|
+
"Content-Type": "application/json",
|
|
93330
|
+
...this.authHeaders()
|
|
93331
|
+
};
|
|
93332
|
+
if (typeof args.expectedVersion === "number") {
|
|
93333
|
+
headers["If-Match"] = `"${args.expectedVersion}"`;
|
|
93334
|
+
}
|
|
93335
|
+
const res = await this.fetchImpl(url, {
|
|
93336
|
+
method: "PUT",
|
|
93337
|
+
headers,
|
|
93338
|
+
body: JSON.stringify({ ...args.tree, ...guardBody2(args.expectedVersion) })
|
|
93339
|
+
});
|
|
93340
|
+
const parsed = await this.readBody(res);
|
|
93341
|
+
if (!res.ok) throw this.toError(res, parsed);
|
|
93342
|
+
const etagVersion = parseETagVersion2(res.headers);
|
|
93343
|
+
const v = (parsed && parsed.version) ?? etagVersion;
|
|
93344
|
+
return { version: typeof v === "number" ? v : (args.expectedVersion ?? 0) + 1 };
|
|
93345
|
+
}
|
|
93346
|
+
/**
|
|
93347
|
+
* Delete the native CURRENCY budget. Whole-year delete is idempotent (204).
|
|
93348
|
+
* The optimistic guard rides both `If-Match` and body `expectedVersion`.
|
|
93349
|
+
*/
|
|
93350
|
+
async deleteBudget(args) {
|
|
93351
|
+
const qs = new URLSearchParams();
|
|
93352
|
+
qs.set("domain", args.domain);
|
|
93353
|
+
qs.set("year", String(args.year));
|
|
93354
|
+
qs.set("measure", "CURRENCY");
|
|
93355
|
+
const url = joinUrl2(this.cfg.baseUrl, this.basePath, `${this.goalsPath(args)}?${qs.toString()}`);
|
|
93356
|
+
const headers = { Accept: "application/json", ...this.authHeaders() };
|
|
93357
|
+
const init = { method: "DELETE", headers };
|
|
93358
|
+
if (typeof args.expectedVersion === "number") {
|
|
93359
|
+
headers["If-Match"] = `"${args.expectedVersion}"`;
|
|
93360
|
+
headers["Content-Type"] = "application/json";
|
|
93361
|
+
init.body = JSON.stringify(guardBody2(args.expectedVersion));
|
|
93362
|
+
}
|
|
93363
|
+
const res = await this.fetchImpl(url, init);
|
|
93364
|
+
if (res.status === 204) return {};
|
|
93365
|
+
const body = await this.readBody(res);
|
|
93366
|
+
if (!res.ok) throw this.toError(res, body);
|
|
93367
|
+
const etagVersion = parseETagVersion2(res.headers);
|
|
93368
|
+
const v = (body && body.version) ?? etagVersion;
|
|
93369
|
+
return typeof v === "number" ? { version: v } : {};
|
|
93370
|
+
}
|
|
93371
|
+
async readBody(res) {
|
|
93372
|
+
try {
|
|
93373
|
+
const text2 = await res.text();
|
|
93374
|
+
if (!text2) return null;
|
|
93375
|
+
return JSON.parse(text2);
|
|
93376
|
+
} catch {
|
|
93377
|
+
return null;
|
|
93378
|
+
}
|
|
93379
|
+
}
|
|
93380
|
+
toError(res, body) {
|
|
93381
|
+
const err = body && body.error;
|
|
93382
|
+
if (err && typeof err === "object") {
|
|
93383
|
+
const e = err;
|
|
93384
|
+
return new GoalsMoneyApiError(e.code || `HTTP_${res.status}`, res.status, e.message, e.details);
|
|
93385
|
+
}
|
|
93386
|
+
return new GoalsMoneyApiError(`HTTP_${res.status}`, res.status, res.statusText);
|
|
93387
|
+
}
|
|
93388
|
+
};
|
|
93389
|
+
function createGoalsMoneyClient(config2) {
|
|
93390
|
+
return new GoalsMoneyClient(config2);
|
|
93391
|
+
}
|
|
93392
|
+
|
|
93393
|
+
// src/components/financial-goals/budgetView.ts
|
|
93394
|
+
var DEFAULT_VALUE_COLORS2 = {
|
|
93395
|
+
target: "#7c3aed",
|
|
93396
|
+
projected: "#2563eb"
|
|
93397
|
+
};
|
|
93398
|
+
var DEFAULT_CHIP3 = {
|
|
93399
|
+
overBg: "#fee2e2",
|
|
93400
|
+
overText: "#b91c1c",
|
|
93401
|
+
withinBg: "#dcfce7",
|
|
93402
|
+
withinText: "#15803d",
|
|
93403
|
+
neutralBg: "#f1f5f9",
|
|
93404
|
+
neutralText: "#64748b"
|
|
93405
|
+
};
|
|
93406
|
+
var CHIP_BASE3 = "border-radius:999px;padding:3px 12px;font:800 12px Nunito,sans-serif;white-space:nowrap;display:inline-flex;align-items:center;gap:6px;";
|
|
93407
|
+
function hasAmount4(s) {
|
|
93408
|
+
return typeof s === "string" && s.trim() !== "";
|
|
93409
|
+
}
|
|
93410
|
+
function resolveBudget(overlay) {
|
|
93411
|
+
if (!overlay || typeof overlay.state !== "string") {
|
|
93412
|
+
return void 0;
|
|
93413
|
+
}
|
|
93414
|
+
if (overlay.state !== "available") return void 0;
|
|
93415
|
+
return overlay.budget;
|
|
93416
|
+
}
|
|
93417
|
+
function figureHTML2(label, amount, color) {
|
|
93418
|
+
return `<span style="display:inline-flex;align-items:center;gap:4px;white-space:nowrap;"><span style="color:${color};font-weight:700;">${label}</span><b style="color:var(--gc-text2, #334155);font-weight:800;">${formatBRL(amount ?? null)}</b></span>`;
|
|
93419
|
+
}
|
|
93420
|
+
function buildVerdictHTML(budget, chipColors) {
|
|
93421
|
+
const withinBudget = budget.verdict?.withinBudget;
|
|
93422
|
+
const varianceR$ = hasAmount4(budget.verdict?.variance) ? formatBRLDelta(budget.verdict.variance) : DASH;
|
|
93423
|
+
const pct = computeDeltaPct(
|
|
93424
|
+
budget.projected?.amount ?? null,
|
|
93425
|
+
budget.target?.amount ?? null
|
|
93426
|
+
);
|
|
93427
|
+
const pctTxt = pct == null ? DASH : formatDeltaPct(pct);
|
|
93428
|
+
const varianceLabel = varianceR$ === DASH && pctTxt === DASH ? "" : `<span class="myio-budget__variance" style="font-weight:700;margin-left:8px;color:var(--gc-muted, #64748b);">${varianceR$} \xB7 ${pctTxt}</span>`;
|
|
93429
|
+
if (withinBudget === true) {
|
|
93430
|
+
return `<span data-budget-verdict="within" style="background:${chipColors.withinBg};color:${chipColors.withinText};${CHIP_BASE3}"><span aria-hidden="true">\u2713</span>Dentro do or\xE7amento</span>${varianceLabel}`;
|
|
93431
|
+
}
|
|
93432
|
+
if (withinBudget === false) {
|
|
93433
|
+
return `<span data-budget-verdict="over" style="background:${chipColors.overBg};color:${chipColors.overText};${CHIP_BASE3}"><span aria-hidden="true">\u25B2</span>Acima do or\xE7amento</span>${varianceLabel}`;
|
|
93434
|
+
}
|
|
93435
|
+
return `<span data-budget-verdict="withheld" style="background:${chipColors.neutralBg};color:${chipColors.neutralText};${CHIP_BASE3}"><span aria-hidden="true">\u23F3</span>Veredito indispon\xEDvel \u2014 cobertura incompleta</span>`;
|
|
93436
|
+
}
|
|
93437
|
+
function buildBudgetHTML(budget, chipColors = DEFAULT_CHIP3, valueColors = DEFAULT_VALUE_COLORS2) {
|
|
93438
|
+
const figures = `<div style="font:600 12px Nunito,sans-serif;color:var(--gc-muted, #64748b);display:flex;align-items:center;gap:14px;flex-wrap:wrap;min-width:0;"><span aria-hidden="true">\u{1F3AF}</span>` + figureHTML2("Meta (or\xE7amento)", budget.target?.amount, valueColors.target) + figureHTML2("Proje\xE7\xE3o", budget.projected?.amount, valueColors.projected) + `</div>`;
|
|
93439
|
+
return `<div class="myio-budget__row" data-budget-row="1" style="display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap;">` + figures + `<span class="myio-budget__verdict-wrap" style="display:inline-flex;align-items:center;">` + buildVerdictHTML(budget, chipColors) + `</span></div><div class="myio-budget__note" style="font:600 10px Nunito,sans-serif;color:var(--gc-muted, #94a3b8);margin-top:4px;">Or\xE7amento nativo em R$ \xB7 Proje\xE7\xE3o estimada</div>`;
|
|
93440
|
+
}
|
|
93441
|
+
function emptyStateHTML() {
|
|
93442
|
+
return `<div class="myio-budget__empty" role="status" style="font:600 12px Nunito,sans-serif;color:var(--gc-muted, #94a3b8);display:flex;align-items:center;gap:6px;"><span aria-hidden="true">\u{1F4B8}</span>Nenhum or\xE7amento em R$ definido.</div>`;
|
|
93443
|
+
}
|
|
93444
|
+
function renderBudgetView(options) {
|
|
93445
|
+
const overlay = options?.overlay;
|
|
93446
|
+
if (!overlay || typeof overlay.state !== "string") {
|
|
93447
|
+
return null;
|
|
93448
|
+
}
|
|
93449
|
+
const doc = options.document || (typeof document !== "undefined" ? document : void 0);
|
|
93450
|
+
if (!doc) {
|
|
93451
|
+
throw new Error(
|
|
93452
|
+
"renderBudgetView requires a document (pass options.document in non-DOM envs)."
|
|
93453
|
+
);
|
|
93454
|
+
}
|
|
93455
|
+
const budget = resolveBudget(overlay);
|
|
93456
|
+
const root = doc.createElement("div");
|
|
93457
|
+
root.className = "myio-budget";
|
|
93458
|
+
if (!budget) {
|
|
93459
|
+
root.setAttribute("data-budget-state", "empty");
|
|
93460
|
+
root.innerHTML = emptyStateHTML();
|
|
93461
|
+
return root;
|
|
93462
|
+
}
|
|
93463
|
+
const chipColors = { ...DEFAULT_CHIP3, ...options.chipColors };
|
|
93464
|
+
const valueColors = {
|
|
93465
|
+
...DEFAULT_VALUE_COLORS2,
|
|
93466
|
+
...options.valueColors
|
|
93467
|
+
};
|
|
93468
|
+
root.setAttribute("data-budget-state", "budget");
|
|
93469
|
+
root.innerHTML = buildBudgetHTML(budget, chipColors, valueColors);
|
|
93470
|
+
const withheld = budget.verdict?.withinBudget !== true && budget.verdict?.withinBudget !== false;
|
|
93471
|
+
if (withheld && overlay.state === "available" && overlay.coverageComplete !== true) {
|
|
93472
|
+
const coverageOpts = {
|
|
93473
|
+
onCategorizeDevice: options.onCategorizeDevice,
|
|
93474
|
+
onManageCategories: options.onManageCategories,
|
|
93475
|
+
document: doc
|
|
93476
|
+
};
|
|
93477
|
+
const why = renderCoverageView(overlay, coverageOpts);
|
|
93478
|
+
why.setAttribute("data-budget-why", "1");
|
|
93479
|
+
root.appendChild(why);
|
|
93480
|
+
}
|
|
93481
|
+
if (typeof options.onSaveBudget === "function") {
|
|
93482
|
+
const cb = options.onSaveBudget;
|
|
93483
|
+
const btn = doc.createElement("button");
|
|
93484
|
+
btn.type = "button";
|
|
93485
|
+
btn.className = "myio-budget__edit";
|
|
93486
|
+
btn.setAttribute("data-budget-edit", "1");
|
|
93487
|
+
btn.textContent = "Editar or\xE7amento";
|
|
93488
|
+
btn.setAttribute(
|
|
93489
|
+
"style",
|
|
93490
|
+
"align-self:flex-start;margin-top:8px;padding:6px 12px;border:1px solid #7c3aed;border-radius:8px;background:transparent;color:#7c3aed;font:800 12px Nunito,sans-serif;cursor:pointer;"
|
|
93491
|
+
);
|
|
93492
|
+
btn.addEventListener("click", (ev) => {
|
|
93493
|
+
ev.preventDefault();
|
|
93494
|
+
ev.stopPropagation();
|
|
93495
|
+
const tree = hasAmount4(budget.target?.amount) ? { annual: { value: Number(budget.target.amount) } } : {};
|
|
93496
|
+
cb(tree);
|
|
93497
|
+
});
|
|
93498
|
+
root.appendChild(btn);
|
|
93499
|
+
}
|
|
93500
|
+
return root;
|
|
93501
|
+
}
|
|
93502
|
+
|
|
93503
|
+
// src/components/financial-goals/deviceCategoryPort.ts
|
|
93504
|
+
var DeviceCategoryConflictError = class extends Error {
|
|
93505
|
+
deviceId;
|
|
93506
|
+
code = "DEVICE_CATEGORY_VERSION_CONFLICT";
|
|
93507
|
+
constructor(deviceId, message) {
|
|
93508
|
+
super(message || `Version conflict for device ${deviceId}`);
|
|
93509
|
+
this.name = "DeviceCategoryConflictError";
|
|
93510
|
+
this.deviceId = deviceId;
|
|
93511
|
+
}
|
|
93512
|
+
};
|
|
93513
|
+
function createFakeDeviceCategoryPort(seed = [], options = {}) {
|
|
93514
|
+
const supportsBulk = options.supportsBulk !== false;
|
|
93515
|
+
const latency = Math.max(0, options.latencyMs || 0);
|
|
93516
|
+
const rows = /* @__PURE__ */ new Map();
|
|
93517
|
+
for (const s of seed) {
|
|
93518
|
+
const v = s.version != null ? Number(s.version) || 0 : 0;
|
|
93519
|
+
rows.set(s.deviceId, {
|
|
93520
|
+
deviceId: s.deviceId,
|
|
93521
|
+
code: s.code,
|
|
93522
|
+
label: s.label,
|
|
93523
|
+
tariffCategory: s.tariffCategory ?? null,
|
|
93524
|
+
version: String(v),
|
|
93525
|
+
domain: s.domain,
|
|
93526
|
+
_v: v
|
|
93527
|
+
});
|
|
93528
|
+
}
|
|
93529
|
+
const delay = (value) => latency > 0 ? new Promise((res) => setTimeout(() => res(value), latency)) : Promise.resolve(value);
|
|
93530
|
+
const toRow = (r) => ({
|
|
93531
|
+
deviceId: r.deviceId,
|
|
93532
|
+
code: r.code,
|
|
93533
|
+
label: r.label,
|
|
93534
|
+
tariffCategory: r.tariffCategory,
|
|
93535
|
+
version: r.version
|
|
93536
|
+
});
|
|
93537
|
+
const port = {
|
|
93538
|
+
listDevices(args) {
|
|
93539
|
+
const list = [...rows.values()].filter((r) => !args.domain || !r.domain || r.domain === args.domain).map(toRow);
|
|
93540
|
+
return delay(list);
|
|
93541
|
+
},
|
|
93542
|
+
setCategory(args) {
|
|
93543
|
+
const r = rows.get(args.deviceId);
|
|
93544
|
+
if (!r) {
|
|
93545
|
+
return Promise.reject(new Error(`Unknown device ${args.deviceId}`));
|
|
93546
|
+
}
|
|
93547
|
+
if (args.expectedVersion != null && args.expectedVersion !== r.version) {
|
|
93548
|
+
return Promise.reject(
|
|
93549
|
+
new DeviceCategoryConflictError(
|
|
93550
|
+
args.deviceId,
|
|
93551
|
+
`Version conflict: expected ${args.expectedVersion}, current ${r.version}`
|
|
93552
|
+
)
|
|
93553
|
+
);
|
|
93554
|
+
}
|
|
93555
|
+
r.tariffCategory = args.category;
|
|
93556
|
+
r._v += 1;
|
|
93557
|
+
r.version = String(r._v);
|
|
93558
|
+
return delay(toRow(r));
|
|
93559
|
+
},
|
|
93560
|
+
snapshot() {
|
|
93561
|
+
return [...rows.values()].map(toRow);
|
|
93562
|
+
},
|
|
93563
|
+
bumpVersion(deviceId) {
|
|
93564
|
+
const r = rows.get(deviceId);
|
|
93565
|
+
if (!r) return;
|
|
93566
|
+
r._v += 1;
|
|
93567
|
+
r.version = String(r._v);
|
|
93568
|
+
}
|
|
93569
|
+
};
|
|
93570
|
+
if (supportsBulk) {
|
|
93571
|
+
port.setCategoryBulk = (args) => {
|
|
93572
|
+
const failed = [];
|
|
93573
|
+
let updated = 0;
|
|
93574
|
+
for (const id of args.deviceIds) {
|
|
93575
|
+
const r = rows.get(id);
|
|
93576
|
+
if (!r) {
|
|
93577
|
+
failed.push({ deviceId: id, reason: "UNKNOWN_DEVICE" });
|
|
93578
|
+
continue;
|
|
93579
|
+
}
|
|
93580
|
+
r.tariffCategory = args.category;
|
|
93581
|
+
r._v += 1;
|
|
93582
|
+
r.version = String(r._v);
|
|
93583
|
+
updated += 1;
|
|
93584
|
+
}
|
|
93585
|
+
return delay({ updated, failed });
|
|
93586
|
+
};
|
|
93587
|
+
}
|
|
93588
|
+
return port;
|
|
93589
|
+
}
|
|
93590
|
+
function createHttpDeviceCategoryPort(config2) {
|
|
93591
|
+
void config2;
|
|
93592
|
+
const notReady = () => Promise.reject(
|
|
93593
|
+
new Error(
|
|
93594
|
+
"createHttpDeviceCategoryPort: the GCDR device tariffCategory API (RFC-0228 B6) is not implemented yet. Inject createFakeDeviceCategoryPort for now, or a real DeviceCategoryPort once B6 ships."
|
|
93595
|
+
)
|
|
93596
|
+
);
|
|
93597
|
+
return {
|
|
93598
|
+
listDevices: () => notReady(),
|
|
93599
|
+
setCategory: () => notReady()
|
|
93600
|
+
};
|
|
93601
|
+
}
|
|
93602
|
+
|
|
93603
|
+
// src/components/financial-goals/deviceCategoryStyles.ts
|
|
93604
|
+
var DEVICE_CATEGORY_STYLE_ID = "myio-fin-device-category-styles";
|
|
93605
|
+
var DEVICE_CATEGORY_CSS = `
|
|
93606
|
+
.myio-devcat {
|
|
93607
|
+
--_dc-bg: var(--myio-bg, #ffffff);
|
|
93608
|
+
--_dc-card: var(--myio-card, #f8fafc);
|
|
93609
|
+
--_dc-text: var(--myio-text, #1f2937);
|
|
93610
|
+
--_dc-muted: var(--myio-text-muted, #6b7280);
|
|
93611
|
+
--_dc-border: var(--myio-border, #e5e7eb);
|
|
93612
|
+
--_dc-brand: var(--myio-brand-700, #5b2c9d);
|
|
93613
|
+
--_dc-brand-soft: var(--myio-brand-100, #efe7fb);
|
|
93614
|
+
--_dc-danger-bg: #fef2f2;
|
|
93615
|
+
--_dc-danger-border: #fecaca;
|
|
93616
|
+
--_dc-danger-text: #991b1b;
|
|
93617
|
+
--_dc-focus-bg: #fffbeb;
|
|
93618
|
+
--_dc-focus-border: #f59e0b;
|
|
93619
|
+
position: fixed;
|
|
93620
|
+
inset: 0;
|
|
93621
|
+
z-index: 2147483000;
|
|
93622
|
+
display: flex;
|
|
93623
|
+
align-items: center;
|
|
93624
|
+
justify-content: center;
|
|
93625
|
+
font-family: 'Nunito', system-ui, -apple-system, sans-serif;
|
|
93626
|
+
color: var(--_dc-text);
|
|
93627
|
+
opacity: 0;
|
|
93628
|
+
transition: opacity 0.18s ease;
|
|
93629
|
+
}
|
|
93630
|
+
.myio-devcat.show { opacity: 1; }
|
|
93631
|
+
|
|
93632
|
+
.myio-devcat__overlay {
|
|
93633
|
+
position: absolute;
|
|
93634
|
+
inset: 0;
|
|
93635
|
+
background: rgba(15, 23, 42, 0.55);
|
|
93636
|
+
backdrop-filter: blur(2px);
|
|
93637
|
+
}
|
|
93638
|
+
|
|
93639
|
+
.myio-devcat__card {
|
|
93640
|
+
position: relative;
|
|
93641
|
+
width: min(760px, 94vw);
|
|
93642
|
+
max-height: 90vh;
|
|
93643
|
+
display: flex;
|
|
93644
|
+
flex-direction: column;
|
|
93645
|
+
background: var(--_dc-bg);
|
|
93646
|
+
border: 1px solid var(--_dc-border);
|
|
93647
|
+
border-radius: 16px;
|
|
93648
|
+
box-shadow: 0 24px 60px rgba(15, 23, 42, 0.35);
|
|
93649
|
+
overflow: hidden;
|
|
93650
|
+
}
|
|
93651
|
+
|
|
93652
|
+
.myio-devcat__header {
|
|
93653
|
+
display: flex;
|
|
93654
|
+
align-items: center;
|
|
93655
|
+
justify-content: space-between;
|
|
93656
|
+
gap: 12px;
|
|
93657
|
+
padding: 16px 20px;
|
|
93658
|
+
border-bottom: 1px solid var(--_dc-border);
|
|
93659
|
+
background: var(--_dc-card);
|
|
93660
|
+
}
|
|
93661
|
+
.myio-devcat__title {
|
|
93662
|
+
display: flex;
|
|
93663
|
+
align-items: center;
|
|
93664
|
+
gap: 10px;
|
|
93665
|
+
font-weight: 800;
|
|
93666
|
+
font-size: 16px;
|
|
93667
|
+
margin: 0;
|
|
93668
|
+
}
|
|
93669
|
+
.myio-devcat__close {
|
|
93670
|
+
border: none;
|
|
93671
|
+
background: transparent;
|
|
93672
|
+
color: var(--_dc-muted);
|
|
93673
|
+
font-size: 22px;
|
|
93674
|
+
line-height: 1;
|
|
93675
|
+
cursor: pointer;
|
|
93676
|
+
padding: 4px 8px;
|
|
93677
|
+
border-radius: 8px;
|
|
93678
|
+
}
|
|
93679
|
+
.myio-devcat__close:hover { background: var(--_dc-border); color: var(--_dc-text); }
|
|
93680
|
+
|
|
93681
|
+
.myio-devcat__toolbar {
|
|
93682
|
+
display: flex;
|
|
93683
|
+
flex-wrap: wrap;
|
|
93684
|
+
gap: 10px;
|
|
93685
|
+
align-items: center;
|
|
93686
|
+
padding: 12px 20px;
|
|
93687
|
+
border-bottom: 1px solid var(--_dc-border);
|
|
93688
|
+
}
|
|
93689
|
+
.myio-devcat__search {
|
|
93690
|
+
flex: 1 1 200px;
|
|
93691
|
+
min-width: 140px;
|
|
93692
|
+
padding: 8px 12px;
|
|
93693
|
+
border: 1px solid var(--_dc-border);
|
|
93694
|
+
border-radius: 8px;
|
|
93695
|
+
background: var(--_dc-bg);
|
|
93696
|
+
color: var(--_dc-text);
|
|
93697
|
+
font-family: inherit;
|
|
93698
|
+
font-size: 13px;
|
|
93699
|
+
}
|
|
93700
|
+
.myio-devcat__filter {
|
|
93701
|
+
padding: 8px 12px;
|
|
93702
|
+
border: 1px solid var(--_dc-border);
|
|
93703
|
+
border-radius: 8px;
|
|
93704
|
+
background: var(--_dc-bg);
|
|
93705
|
+
color: var(--_dc-text);
|
|
93706
|
+
font-family: inherit;
|
|
93707
|
+
font-size: 13px;
|
|
93708
|
+
cursor: pointer;
|
|
93709
|
+
}
|
|
93710
|
+
|
|
93711
|
+
.myio-devcat__bulkbar {
|
|
93712
|
+
display: none;
|
|
93713
|
+
align-items: center;
|
|
93714
|
+
flex-wrap: wrap;
|
|
93715
|
+
gap: 10px;
|
|
93716
|
+
padding: 10px 20px;
|
|
93717
|
+
background: var(--_dc-brand-soft);
|
|
93718
|
+
border-bottom: 1px solid var(--_dc-border);
|
|
93719
|
+
font-size: 13px;
|
|
93720
|
+
font-weight: 700;
|
|
93721
|
+
}
|
|
93722
|
+
.myio-devcat__bulkbar.show { display: flex; }
|
|
93723
|
+
.myio-devcat__bulkbar select {
|
|
93724
|
+
padding: 6px 10px;
|
|
93725
|
+
border: 1px solid var(--_dc-border);
|
|
93726
|
+
border-radius: 8px;
|
|
93727
|
+
background: var(--_dc-bg);
|
|
93728
|
+
color: var(--_dc-text);
|
|
93729
|
+
font-family: inherit;
|
|
93730
|
+
font-size: 13px;
|
|
93731
|
+
}
|
|
93732
|
+
.myio-devcat__bulk-apply {
|
|
93733
|
+
padding: 6px 14px;
|
|
93734
|
+
border: none;
|
|
93735
|
+
border-radius: 8px;
|
|
93736
|
+
background: var(--_dc-brand);
|
|
93737
|
+
color: #fff;
|
|
93738
|
+
font-family: inherit;
|
|
93739
|
+
font-weight: 800;
|
|
93740
|
+
font-size: 13px;
|
|
93741
|
+
cursor: pointer;
|
|
93742
|
+
}
|
|
93743
|
+
.myio-devcat__bulk-apply:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
93744
|
+
|
|
93745
|
+
.myio-devcat__body {
|
|
93746
|
+
flex: 1 1 auto;
|
|
93747
|
+
overflow-y: auto;
|
|
93748
|
+
padding: 6px 0;
|
|
93749
|
+
}
|
|
93750
|
+
.myio-devcat__empty {
|
|
93751
|
+
padding: 40px 20px;
|
|
93752
|
+
text-align: center;
|
|
93753
|
+
color: var(--_dc-muted);
|
|
93754
|
+
font-size: 14px;
|
|
93755
|
+
}
|
|
93756
|
+
|
|
93757
|
+
.myio-devcat__row {
|
|
93758
|
+
display: flex;
|
|
93759
|
+
align-items: center;
|
|
93760
|
+
gap: 12px;
|
|
93761
|
+
padding: 10px 20px;
|
|
93762
|
+
border-bottom: 1px solid var(--_dc-border);
|
|
93763
|
+
}
|
|
93764
|
+
.myio-devcat__row[data-focused="1"] {
|
|
93765
|
+
background: var(--_dc-focus-bg);
|
|
93766
|
+
box-shadow: inset 3px 0 0 var(--_dc-focus-border);
|
|
93767
|
+
}
|
|
93768
|
+
.myio-devcat__row-check { flex: 0 0 auto; width: 16px; height: 16px; cursor: pointer; }
|
|
93769
|
+
.myio-devcat__row-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
|
|
93770
|
+
.myio-devcat__row-label {
|
|
93771
|
+
font-weight: 700;
|
|
93772
|
+
font-size: 14px;
|
|
93773
|
+
overflow: hidden;
|
|
93774
|
+
text-overflow: ellipsis;
|
|
93775
|
+
white-space: nowrap;
|
|
93776
|
+
}
|
|
93777
|
+
.myio-devcat__row-code {
|
|
93778
|
+
font-size: 12px;
|
|
93779
|
+
color: var(--_dc-muted);
|
|
93780
|
+
font-variant-numeric: tabular-nums;
|
|
93781
|
+
}
|
|
93782
|
+
.myio-devcat__row-select {
|
|
93783
|
+
flex: 0 0 auto;
|
|
93784
|
+
padding: 7px 10px;
|
|
93785
|
+
border: 1px solid var(--_dc-border);
|
|
93786
|
+
border-radius: 8px;
|
|
93787
|
+
background: var(--_dc-bg);
|
|
93788
|
+
color: var(--_dc-text);
|
|
93789
|
+
font-family: inherit;
|
|
93790
|
+
font-size: 13px;
|
|
93791
|
+
font-weight: 700;
|
|
93792
|
+
cursor: pointer;
|
|
93793
|
+
}
|
|
93794
|
+
.myio-devcat__row[data-cat="null"] .myio-devcat__row-select { color: var(--_dc-muted); }
|
|
93795
|
+
.myio-devcat__row-conflict {
|
|
93796
|
+
display: none;
|
|
93797
|
+
flex: 1 1 100%;
|
|
93798
|
+
margin-top: 6px;
|
|
93799
|
+
padding: 7px 12px;
|
|
93800
|
+
border-radius: 8px;
|
|
93801
|
+
background: var(--_dc-danger-bg);
|
|
93802
|
+
border: 1px solid var(--_dc-danger-border);
|
|
93803
|
+
color: var(--_dc-danger-text);
|
|
93804
|
+
font-size: 12px;
|
|
93805
|
+
font-weight: 700;
|
|
93806
|
+
}
|
|
93807
|
+
.myio-devcat__row[data-conflict="1"] { flex-wrap: wrap; }
|
|
93808
|
+
.myio-devcat__row[data-conflict="1"] .myio-devcat__row-conflict { display: block; }
|
|
93809
|
+
|
|
93810
|
+
.myio-devcat__footer {
|
|
93811
|
+
display: flex;
|
|
93812
|
+
align-items: center;
|
|
93813
|
+
justify-content: space-between;
|
|
93814
|
+
gap: 12px;
|
|
93815
|
+
padding: 12px 20px;
|
|
93816
|
+
border-top: 1px solid var(--_dc-border);
|
|
93817
|
+
background: var(--_dc-card);
|
|
93818
|
+
font-size: 12px;
|
|
93819
|
+
color: var(--_dc-muted);
|
|
93820
|
+
}
|
|
93821
|
+
|
|
93822
|
+
@media (prefers-color-scheme: dark) {
|
|
93823
|
+
.myio-devcat {
|
|
93824
|
+
--_dc-bg: var(--myio-bg, #0f172a);
|
|
93825
|
+
--_dc-card: var(--myio-card, #1e293b);
|
|
93826
|
+
--_dc-text: var(--myio-text, #e2e8f0);
|
|
93827
|
+
--_dc-muted: var(--myio-text-muted, #94a3b8);
|
|
93828
|
+
--_dc-border: var(--myio-border, #334155);
|
|
93829
|
+
--_dc-brand: var(--myio-brand-700, #a78bfa);
|
|
93830
|
+
--_dc-brand-soft: var(--myio-brand-100, #2a2350);
|
|
93831
|
+
--_dc-danger-bg: #3a1414; --_dc-danger-border: #7f1d1d; --_dc-danger-text: #fca5a5;
|
|
93832
|
+
--_dc-focus-bg: #3a2e0a; --_dc-focus-border: #b45309;
|
|
93833
|
+
}
|
|
93834
|
+
}
|
|
93835
|
+
:root[data-theme="dark"] .myio-devcat {
|
|
93836
|
+
--_dc-bg: var(--myio-bg, #0f172a);
|
|
93837
|
+
--_dc-card: var(--myio-card, #1e293b);
|
|
93838
|
+
--_dc-text: var(--myio-text, #e2e8f0);
|
|
93839
|
+
--_dc-muted: var(--myio-text-muted, #94a3b8);
|
|
93840
|
+
--_dc-border: var(--myio-border, #334155);
|
|
93841
|
+
--_dc-brand: var(--myio-brand-700, #a78bfa);
|
|
93842
|
+
--_dc-brand-soft: var(--myio-brand-100, #2a2350);
|
|
93843
|
+
--_dc-danger-bg: #3a1414; --_dc-danger-border: #7f1d1d; --_dc-danger-text: #fca5a5;
|
|
93844
|
+
--_dc-focus-bg: #3a2e0a; --_dc-focus-border: #b45309;
|
|
93845
|
+
}
|
|
93846
|
+
:root[data-theme="light"] .myio-devcat {
|
|
93847
|
+
--_dc-bg: var(--myio-bg, #ffffff);
|
|
93848
|
+
--_dc-card: var(--myio-card, #f8fafc);
|
|
93849
|
+
--_dc-text: var(--myio-text, #1f2937);
|
|
93850
|
+
--_dc-muted: var(--myio-text-muted, #6b7280);
|
|
93851
|
+
--_dc-border: var(--myio-border, #e5e7eb);
|
|
93852
|
+
--_dc-brand: var(--myio-brand-700, #5b2c9d);
|
|
93853
|
+
--_dc-brand-soft: var(--myio-brand-100, #efe7fb);
|
|
93854
|
+
--_dc-danger-bg: #fef2f2; --_dc-danger-border: #fecaca; --_dc-danger-text: #991b1b;
|
|
93855
|
+
--_dc-focus-bg: #fffbeb; --_dc-focus-border: #f59e0b;
|
|
93856
|
+
}
|
|
93857
|
+
`;
|
|
93858
|
+
function injectDeviceCategoryStyles(doc) {
|
|
93859
|
+
if (!doc || !doc.head) return;
|
|
93860
|
+
if (doc.getElementById(DEVICE_CATEGORY_STYLE_ID)) return;
|
|
93861
|
+
const style = doc.createElement("style");
|
|
93862
|
+
style.id = DEVICE_CATEGORY_STYLE_ID;
|
|
93863
|
+
style.textContent = DEVICE_CATEGORY_CSS;
|
|
93864
|
+
doc.head.appendChild(style);
|
|
93865
|
+
}
|
|
93866
|
+
|
|
93867
|
+
// src/components/financial-goals/deviceCategoryPanel.ts
|
|
93868
|
+
var PANEL_TERM_LABEL = {
|
|
93869
|
+
lojas: "Lojas",
|
|
93870
|
+
area_comum: "\xC1rea Comum"
|
|
93871
|
+
};
|
|
93872
|
+
var NONE_LABEL = "\u2014 Sem categoria \u2014";
|
|
93873
|
+
function deviceCategoryLabel(cat) {
|
|
93874
|
+
if (cat == null) return NONE_LABEL;
|
|
93875
|
+
return PANEL_TERM_LABEL[wireCategoryToPanel(cat)];
|
|
93876
|
+
}
|
|
93877
|
+
function deviceCategoryToPanelTerm(cat) {
|
|
93878
|
+
return cat == null ? null : wireCategoryToPanel(cat);
|
|
93879
|
+
}
|
|
93880
|
+
function panelTermToDeviceCategory(term) {
|
|
93881
|
+
return term == null ? null : panelCategoryToWire(term);
|
|
93882
|
+
}
|
|
93883
|
+
function esc7(s) {
|
|
93884
|
+
return String(s ?? "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
93885
|
+
}
|
|
93886
|
+
function categoryOptionsHTML(selected) {
|
|
93887
|
+
const opt = (value, label, isSel) => `<option value="${value}"${isSel ? " selected" : ""}>${esc7(label)}</option>`;
|
|
93888
|
+
return opt("", NONE_LABEL, selected == null) + opt("COMMON_AREA", deviceCategoryLabel("COMMON_AREA"), selected === "COMMON_AREA") + opt("SPECIFIC", deviceCategoryLabel("SPECIFIC"), selected === "SPECIFIC");
|
|
93889
|
+
}
|
|
93890
|
+
function openDeviceCategoryPanel(params) {
|
|
93891
|
+
const doc = params.document || (typeof document !== "undefined" ? document : void 0);
|
|
93892
|
+
if (!doc) {
|
|
93893
|
+
throw new Error(
|
|
93894
|
+
"openDeviceCategoryPanel requires a document (pass params.document in non-DOM envs)."
|
|
93895
|
+
);
|
|
93896
|
+
}
|
|
93897
|
+
injectDeviceCategoryStyles(doc);
|
|
93898
|
+
const { port, customerId } = params;
|
|
93899
|
+
let rows = [];
|
|
93900
|
+
let search = "";
|
|
93901
|
+
let filter = params.initialFilter || "all";
|
|
93902
|
+
const selected = /* @__PURE__ */ new Set();
|
|
93903
|
+
const root = doc.createElement("div");
|
|
93904
|
+
root.className = "myio-devcat";
|
|
93905
|
+
root.setAttribute("data-devcat", "1");
|
|
93906
|
+
if (params.theme) {
|
|
93907
|
+
for (const [k, v] of Object.entries(params.theme)) {
|
|
93908
|
+
if (k.startsWith("--") && typeof v === "string") root.style.setProperty(k, v);
|
|
93909
|
+
}
|
|
93910
|
+
}
|
|
93911
|
+
root.innerHTML = `
|
|
93912
|
+
<div class="myio-devcat__overlay" data-devcat-overlay="1"></div>
|
|
93913
|
+
<div class="myio-devcat__card" role="dialog" aria-modal="true" aria-label="Categorias de tarifa por dispositivo">
|
|
93914
|
+
<div class="myio-devcat__header">
|
|
93915
|
+
<h3 class="myio-devcat__title"><span aria-hidden="true">\u{1F3F7}\uFE0F</span>Categorias de tarifa por dispositivo</h3>
|
|
93916
|
+
<button type="button" class="myio-devcat__close" data-devcat-close="1" aria-label="Fechar">×</button>
|
|
93917
|
+
</div>
|
|
93918
|
+
<div class="myio-devcat__toolbar">
|
|
93919
|
+
<input type="search" class="myio-devcat__search" data-devcat-search="1"
|
|
93920
|
+
placeholder="Buscar por nome ou c\xF3digo\u2026" aria-label="Buscar dispositivo" />
|
|
93921
|
+
<select class="myio-devcat__filter" data-devcat-filter="1" aria-label="Filtrar por categoria">
|
|
93922
|
+
<option value="all">Todas as categorias</option>
|
|
93923
|
+
<option value="uncategorized">Sem categoria</option>
|
|
93924
|
+
<option value="COMMON_AREA">${esc7(deviceCategoryLabel("COMMON_AREA"))}</option>
|
|
93925
|
+
<option value="SPECIFIC">${esc7(deviceCategoryLabel("SPECIFIC"))}</option>
|
|
93926
|
+
</select>
|
|
93927
|
+
<label class="myio-devcat__filter" style="display:flex;align-items:center;gap:6px;cursor:pointer;">
|
|
93928
|
+
<input type="checkbox" data-devcat-selectall="1" /> Selecionar vis\xEDveis
|
|
93929
|
+
</label>
|
|
93930
|
+
</div>
|
|
93931
|
+
<div class="myio-devcat__bulkbar" data-devcat-bulkbar="1">
|
|
93932
|
+
<span data-devcat-bulkcount="1">0 selecionados</span>
|
|
93933
|
+
<select data-devcat-bulkcat="1" aria-label="Categoria para os selecionados">
|
|
93934
|
+
<option value="">${esc7(NONE_LABEL)}</option>
|
|
93935
|
+
<option value="COMMON_AREA">${esc7(deviceCategoryLabel("COMMON_AREA"))}</option>
|
|
93936
|
+
<option value="SPECIFIC">${esc7(deviceCategoryLabel("SPECIFIC"))}</option>
|
|
93937
|
+
</select>
|
|
93938
|
+
<button type="button" class="myio-devcat__bulk-apply" data-devcat-bulkapply="1">Aplicar a selecionados</button>
|
|
93939
|
+
</div>
|
|
93940
|
+
<div class="myio-devcat__body" data-devcat-body="1"></div>
|
|
93941
|
+
<div class="myio-devcat__footer">
|
|
93942
|
+
<span data-devcat-count="1"></span>
|
|
93943
|
+
<span>Categoria expl\xEDcita \u2014 nunca inferida do nome (RFC-0207).</span>
|
|
93944
|
+
</div>
|
|
93945
|
+
</div>
|
|
93946
|
+
`;
|
|
93947
|
+
const body = root.querySelector("[data-devcat-body]");
|
|
93948
|
+
const countEl = root.querySelector("[data-devcat-count]");
|
|
93949
|
+
const bulkbar = root.querySelector("[data-devcat-bulkbar]");
|
|
93950
|
+
const bulkCountEl = root.querySelector("[data-devcat-bulkcount]");
|
|
93951
|
+
const selectAll = root.querySelector("[data-devcat-selectall]");
|
|
93952
|
+
function matchesFilter(r) {
|
|
93953
|
+
if (filter === "all") return true;
|
|
93954
|
+
if (filter === "uncategorized") return r.tariffCategory == null;
|
|
93955
|
+
return r.tariffCategory === filter;
|
|
93956
|
+
}
|
|
93957
|
+
function matchesSearch(r) {
|
|
93958
|
+
if (!search) return true;
|
|
93959
|
+
const hay = `${r.label || ""} ${r.code || ""}`.toLowerCase();
|
|
93960
|
+
return hay.includes(search.toLowerCase());
|
|
93961
|
+
}
|
|
93962
|
+
function visibleRows() {
|
|
93963
|
+
return rows.filter((r) => matchesFilter(r) && matchesSearch(r));
|
|
93964
|
+
}
|
|
93965
|
+
function rowHTML(r) {
|
|
93966
|
+
const name = esc7(r.label || r.code || r.deviceId);
|
|
93967
|
+
const code = r.code ? `<span class="myio-devcat__row-code">${esc7(r.code)}</span>` : "";
|
|
93968
|
+
const checked = selected.has(r.deviceId) ? " checked" : "";
|
|
93969
|
+
const focused = r.deviceId === params.focusDeviceId ? ' data-focused="1"' : "";
|
|
93970
|
+
const catAttr = r.tariffCategory == null ? "null" : r.tariffCategory;
|
|
93971
|
+
return `<div class="myio-devcat__row" data-devcat-row="${esc7(r.deviceId)}" data-cat="${catAttr}"${focused}><input type="checkbox" class="myio-devcat__row-check" data-devcat-rowcheck="${esc7(
|
|
93972
|
+
r.deviceId
|
|
93973
|
+
)}"${checked} aria-label="Selecionar ${name}" /><div class="myio-devcat__row-main"><span class="myio-devcat__row-label" title="${name}">${name}</span>` + code + `</div><select class="myio-devcat__row-select" data-devcat-rowselect="${esc7(
|
|
93974
|
+
r.deviceId
|
|
93975
|
+
)}" aria-label="Categoria de ${name}">${categoryOptionsHTML(r.tariffCategory)}</select><div class="myio-devcat__row-conflict" data-devcat-conflict="${esc7(r.deviceId)}"></div></div>`;
|
|
93976
|
+
}
|
|
93977
|
+
function render3() {
|
|
93978
|
+
const vis = visibleRows();
|
|
93979
|
+
if (vis.length === 0) {
|
|
93980
|
+
body.innerHTML = `<div class="myio-devcat__empty">Nenhum dispositivo encontrado.</div>`;
|
|
93981
|
+
} else {
|
|
93982
|
+
body.innerHTML = vis.map(rowHTML).join("");
|
|
93983
|
+
}
|
|
93984
|
+
countEl.textContent = `${vis.length} de ${rows.length} dispositivo(s)`;
|
|
93985
|
+
wireRows();
|
|
93986
|
+
updateBulkBar();
|
|
93987
|
+
if (params.focusDeviceId) {
|
|
93988
|
+
const el2 = body.querySelector(
|
|
93989
|
+
`[data-devcat-row="${cssEscape(params.focusDeviceId)}"]`
|
|
93990
|
+
);
|
|
93991
|
+
if (el2 && typeof el2.scrollIntoView === "function") {
|
|
93992
|
+
el2.scrollIntoView({ block: "center" });
|
|
93993
|
+
}
|
|
93994
|
+
}
|
|
93995
|
+
}
|
|
93996
|
+
function updateBulkBar() {
|
|
93997
|
+
const n = selected.size;
|
|
93998
|
+
bulkCountEl.textContent = `${n} selecionado(s)`;
|
|
93999
|
+
bulkbar.classList.toggle("show", n > 0);
|
|
94000
|
+
}
|
|
94001
|
+
function wireRows() {
|
|
94002
|
+
body.querySelectorAll("[data-devcat-rowselect]").forEach((sel) => {
|
|
94003
|
+
sel.addEventListener("change", () => {
|
|
94004
|
+
const id = sel.getAttribute("data-devcat-rowselect");
|
|
94005
|
+
const value = sel.value;
|
|
94006
|
+
const category = value === "" ? null : value;
|
|
94007
|
+
void applySingle(id, category);
|
|
94008
|
+
});
|
|
94009
|
+
});
|
|
94010
|
+
body.querySelectorAll("[data-devcat-rowcheck]").forEach((cb) => {
|
|
94011
|
+
cb.addEventListener("change", () => {
|
|
94012
|
+
const id = cb.getAttribute("data-devcat-rowcheck");
|
|
94013
|
+
if (cb.checked) selected.add(id);
|
|
94014
|
+
else selected.delete(id);
|
|
94015
|
+
updateBulkBar();
|
|
94016
|
+
});
|
|
94017
|
+
});
|
|
94018
|
+
}
|
|
94019
|
+
function showConflict(deviceId, message) {
|
|
94020
|
+
const rowEl = body.querySelector(
|
|
94021
|
+
`[data-devcat-row="${cssEscape(deviceId)}"]`
|
|
94022
|
+
);
|
|
94023
|
+
const banner = body.querySelector(
|
|
94024
|
+
`[data-devcat-conflict="${cssEscape(deviceId)}"]`
|
|
94025
|
+
);
|
|
94026
|
+
if (rowEl) rowEl.setAttribute("data-conflict", "1");
|
|
94027
|
+
if (banner) banner.textContent = message;
|
|
94028
|
+
}
|
|
94029
|
+
function clearConflict(deviceId) {
|
|
94030
|
+
const rowEl = body.querySelector(
|
|
94031
|
+
`[data-devcat-row="${cssEscape(deviceId)}"]`
|
|
94032
|
+
);
|
|
94033
|
+
const banner = body.querySelector(
|
|
94034
|
+
`[data-devcat-conflict="${cssEscape(deviceId)}"]`
|
|
94035
|
+
);
|
|
94036
|
+
if (rowEl) rowEl.removeAttribute("data-conflict");
|
|
94037
|
+
if (banner) banner.textContent = "";
|
|
94038
|
+
}
|
|
94039
|
+
async function applySingle(deviceId, category) {
|
|
94040
|
+
const row = rows.find((r) => r.deviceId === deviceId);
|
|
94041
|
+
if (!row) return;
|
|
94042
|
+
clearConflict(deviceId);
|
|
94043
|
+
try {
|
|
94044
|
+
const updated = await port.setCategory({
|
|
94045
|
+
deviceId,
|
|
94046
|
+
category,
|
|
94047
|
+
expectedVersion: row.version
|
|
94048
|
+
});
|
|
94049
|
+
row.tariffCategory = updated.tariffCategory;
|
|
94050
|
+
row.version = updated.version;
|
|
94051
|
+
const rowEl = body.querySelector(
|
|
94052
|
+
`[data-devcat-row="${cssEscape(deviceId)}"]`
|
|
94053
|
+
);
|
|
94054
|
+
if (rowEl) rowEl.setAttribute("data-cat", updated.tariffCategory == null ? "null" : updated.tariffCategory);
|
|
94055
|
+
} catch (err) {
|
|
94056
|
+
const isConflict = err instanceof DeviceCategoryConflictError || err?.code === "DEVICE_CATEGORY_VERSION_CONFLICT";
|
|
94057
|
+
showConflict(
|
|
94058
|
+
deviceId,
|
|
94059
|
+
isConflict ? "Este dispositivo foi alterado por outra pessoa. Recarregue para ver a vers\xE3o atual e reaplique." : `N\xE3o foi poss\xEDvel salvar: ${err?.message || "erro desconhecido"}`
|
|
94060
|
+
);
|
|
94061
|
+
}
|
|
94062
|
+
}
|
|
94063
|
+
async function applyBulk(category) {
|
|
94064
|
+
const ids = [...selected];
|
|
94065
|
+
if (ids.length === 0) return;
|
|
94066
|
+
if (typeof port.setCategoryBulk === "function") {
|
|
94067
|
+
const res = await port.setCategoryBulk({ deviceIds: ids, category });
|
|
94068
|
+
const failedIds = new Set(res.failed.map((f) => f.deviceId));
|
|
94069
|
+
for (const id of ids) {
|
|
94070
|
+
const row = rows.find((r) => r.deviceId === id);
|
|
94071
|
+
if (row && !failedIds.has(id)) {
|
|
94072
|
+
row.tariffCategory = category;
|
|
94073
|
+
if (row.version != null) row.version = String((Number(row.version) || 0) + 1);
|
|
94074
|
+
}
|
|
94075
|
+
}
|
|
94076
|
+
for (const f of res.failed) showConflict(f.deviceId, `Falha: ${f.reason}`);
|
|
94077
|
+
} else {
|
|
94078
|
+
await Promise.all(ids.map((id) => applySingle(id, category)));
|
|
94079
|
+
}
|
|
94080
|
+
render3();
|
|
94081
|
+
}
|
|
94082
|
+
const searchEl = root.querySelector("[data-devcat-search]");
|
|
94083
|
+
const filterEl = root.querySelector("[data-devcat-filter]");
|
|
94084
|
+
filterEl.value = filter;
|
|
94085
|
+
searchEl.addEventListener("input", () => {
|
|
94086
|
+
search = searchEl.value;
|
|
94087
|
+
render3();
|
|
94088
|
+
});
|
|
94089
|
+
filterEl.addEventListener("change", () => {
|
|
94090
|
+
filter = filterEl.value;
|
|
94091
|
+
render3();
|
|
94092
|
+
});
|
|
94093
|
+
selectAll.addEventListener("change", () => {
|
|
94094
|
+
const vis = visibleRows();
|
|
94095
|
+
if (selectAll.checked) vis.forEach((r) => selected.add(r.deviceId));
|
|
94096
|
+
else vis.forEach((r) => selected.delete(r.deviceId));
|
|
94097
|
+
render3();
|
|
94098
|
+
});
|
|
94099
|
+
root.querySelector("[data-devcat-bulkapply]").addEventListener("click", () => {
|
|
94100
|
+
const bulkCat = root.querySelector("[data-devcat-bulkcat]").value;
|
|
94101
|
+
const category = bulkCat === "" ? null : bulkCat;
|
|
94102
|
+
void applyBulk(category);
|
|
94103
|
+
});
|
|
94104
|
+
let closed = false;
|
|
94105
|
+
function close() {
|
|
94106
|
+
if (closed) return;
|
|
94107
|
+
closed = true;
|
|
94108
|
+
root.classList.remove("show");
|
|
94109
|
+
doc.removeEventListener("keydown", escHandler);
|
|
94110
|
+
const remove = () => {
|
|
94111
|
+
if (root.parentNode) root.parentNode.removeChild(root);
|
|
94112
|
+
};
|
|
94113
|
+
if (typeof setTimeout === "function") setTimeout(remove, 180);
|
|
94114
|
+
else remove();
|
|
94115
|
+
params.onClose?.();
|
|
94116
|
+
}
|
|
94117
|
+
function escHandler(e) {
|
|
94118
|
+
if (e.key === "Escape") close();
|
|
94119
|
+
}
|
|
94120
|
+
root.querySelector("[data-devcat-close]")?.addEventListener("click", close);
|
|
94121
|
+
root.querySelector("[data-devcat-overlay]")?.addEventListener("click", close);
|
|
94122
|
+
doc.addEventListener("keydown", escHandler);
|
|
94123
|
+
(doc.body || doc.documentElement).appendChild(root);
|
|
94124
|
+
if (typeof requestAnimationFrame === "function") {
|
|
94125
|
+
requestAnimationFrame(() => root.classList.add("show"));
|
|
94126
|
+
} else {
|
|
94127
|
+
root.classList.add("show");
|
|
94128
|
+
}
|
|
94129
|
+
async function load() {
|
|
94130
|
+
body.innerHTML = `<div class="myio-devcat__empty">Carregando dispositivos\u2026</div>`;
|
|
94131
|
+
try {
|
|
94132
|
+
rows = await port.listDevices({ customerId, domain: params.domain });
|
|
94133
|
+
} catch (err) {
|
|
94134
|
+
rows = [];
|
|
94135
|
+
body.innerHTML = `<div class="myio-devcat__empty">N\xE3o foi poss\xEDvel carregar os dispositivos: ${esc7(
|
|
94136
|
+
err?.message || "erro"
|
|
94137
|
+
)}</div>`;
|
|
94138
|
+
countEl.textContent = "";
|
|
94139
|
+
return;
|
|
94140
|
+
}
|
|
94141
|
+
render3();
|
|
94142
|
+
}
|
|
94143
|
+
const ready = load();
|
|
94144
|
+
return {
|
|
94145
|
+
ready,
|
|
94146
|
+
close,
|
|
94147
|
+
getRoot: () => root,
|
|
94148
|
+
refresh: () => load(),
|
|
94149
|
+
getRows: () => rows.map((r) => ({ ...r })),
|
|
94150
|
+
getVisibleDeviceIds: () => visibleRows().map((r) => r.deviceId),
|
|
94151
|
+
setSearch: (text2) => {
|
|
94152
|
+
search = text2;
|
|
94153
|
+
searchEl.value = text2;
|
|
94154
|
+
render3();
|
|
94155
|
+
},
|
|
94156
|
+
setCategoryFilter: (f) => {
|
|
94157
|
+
filter = f;
|
|
94158
|
+
filterEl.value = f;
|
|
94159
|
+
render3();
|
|
94160
|
+
}
|
|
94161
|
+
};
|
|
94162
|
+
}
|
|
94163
|
+
function createCoverageDeepLink(config2) {
|
|
94164
|
+
const open = (focusDeviceId, initialFilter) => openDeviceCategoryPanel({
|
|
94165
|
+
port: config2.port,
|
|
94166
|
+
customerId: config2.customerId,
|
|
94167
|
+
domain: config2.domain,
|
|
94168
|
+
focusDeviceId,
|
|
94169
|
+
initialFilter,
|
|
94170
|
+
theme: config2.theme,
|
|
94171
|
+
document: config2.document
|
|
94172
|
+
});
|
|
94173
|
+
return {
|
|
94174
|
+
// Deep-link from one uncategorized device → open focused on it.
|
|
94175
|
+
onCategorizeDevice: (deviceId) => open(deviceId),
|
|
94176
|
+
// Generic "manage categories" → open pre-filtered to the uncategorized set.
|
|
94177
|
+
onManageCategories: () => open(void 0, "uncategorized")
|
|
94178
|
+
};
|
|
94179
|
+
}
|
|
94180
|
+
function cssEscape(s) {
|
|
94181
|
+
if (typeof globalThis.CSS?.escape === "function") {
|
|
94182
|
+
return globalThis.CSS.escape(s);
|
|
94183
|
+
}
|
|
94184
|
+
return String(s).replace(/["\\\]#.:>~+*^$|()[{}]/g, "\\$&");
|
|
94185
|
+
}
|
|
94186
|
+
|
|
94187
|
+
// src/components/financial-goals/moneyRolloutGate.ts
|
|
94188
|
+
function normalizeAllowlist(list) {
|
|
94189
|
+
const out = /* @__PURE__ */ new Set();
|
|
94190
|
+
if (!list) return out;
|
|
94191
|
+
const iter = list instanceof Set ? list : Array.isArray(list) ? list : [];
|
|
94192
|
+
for (const raw of iter) {
|
|
94193
|
+
const id = String(raw ?? "").trim();
|
|
94194
|
+
if (id) out.add(id);
|
|
94195
|
+
}
|
|
94196
|
+
return out;
|
|
94197
|
+
}
|
|
94198
|
+
function normalizeId(customerId) {
|
|
94199
|
+
return customerId == null ? "" : String(customerId).trim();
|
|
94200
|
+
}
|
|
94201
|
+
function isBrokenOverlay(overlay) {
|
|
94202
|
+
return !!overlay && overlay.state === "unavailable";
|
|
94203
|
+
}
|
|
94204
|
+
function isCustomerEligible(params, settings) {
|
|
94205
|
+
if (settings && settings.goalsMoneyRolloutBaseWide === true) return true;
|
|
94206
|
+
const set = normalizeAllowlist(params.allowlist ?? settings?.goalsMoneyRolloutAllowlist);
|
|
94207
|
+
if (set.has("*")) return true;
|
|
94208
|
+
const id = normalizeId(params.customerId);
|
|
94209
|
+
if (!id) return false;
|
|
94210
|
+
return set.has(id);
|
|
94211
|
+
}
|
|
94212
|
+
function resolveMoneyRollout(params) {
|
|
94213
|
+
const p = params || {};
|
|
94214
|
+
const settings = p.settings ?? null;
|
|
94215
|
+
const featureAvailable = typeof p.featureAvailable === "boolean" ? p.featureAvailable : !!(settings && settings.goalsMoneyApi);
|
|
94216
|
+
if (!featureAvailable) return { enabled: false, reason: "disabled" };
|
|
94217
|
+
if (!isCustomerEligible(p, settings)) {
|
|
94218
|
+
return { enabled: false, reason: "not-eligible" };
|
|
94219
|
+
}
|
|
94220
|
+
if (isBrokenOverlay(p.overlaySample)) {
|
|
94221
|
+
return { enabled: false, reason: "coverage-gap" };
|
|
94222
|
+
}
|
|
94223
|
+
return { enabled: true, reason: "eligible" };
|
|
94224
|
+
}
|
|
94225
|
+
function routeMoneyRender(params) {
|
|
94226
|
+
const decision = resolveMoneyRollout(params);
|
|
94227
|
+
if (decision.reason === "disabled") {
|
|
94228
|
+
return { decision, action: "render-nothing" };
|
|
94229
|
+
}
|
|
94230
|
+
if (decision.enabled) {
|
|
94231
|
+
return { decision, action: "render-money" };
|
|
94232
|
+
}
|
|
94233
|
+
const sample = params?.overlaySample;
|
|
94234
|
+
const coverageOverlay = sample && sample.state === "unavailable" ? sample : { state: "unavailable", reason: MONEY_REQUIRES_DEVICE_GRANULARITY };
|
|
94235
|
+
return { decision, action: "render-coverage", coverageOverlay };
|
|
94236
|
+
}
|
|
94237
|
+
function renderGatedMoney(params, renderers) {
|
|
94238
|
+
const routing = routeMoneyRender(params);
|
|
94239
|
+
if (routing.action === "render-nothing") return null;
|
|
94240
|
+
if (routing.action === "render-money") {
|
|
94241
|
+
return renderers.renderMoney(params?.overlaySample);
|
|
94242
|
+
}
|
|
94243
|
+
return renderers.renderCoverage(routing.coverageOverlay);
|
|
94244
|
+
}
|
|
94245
|
+
|
|
91639
94246
|
// src/components/premium-modals/measurement-setup/types.ts
|
|
91640
94247
|
var WATER_UNITS = [
|
|
91641
94248
|
{ value: "m3", label: "Metros C\xFAbicos (m\xB3)" },
|
|
@@ -113497,6 +116104,7 @@ var CustomerGoalsCard = class {
|
|
|
113497
116104
|
if (partial.title !== void 0) this.params.title = partial.title;
|
|
113498
116105
|
if (partial.series !== void 0) this.params.series = { ...partial.series };
|
|
113499
116106
|
if (partial.totals !== void 0) this.params.totals = partial.totals;
|
|
116107
|
+
if (partial.moneyVariance !== void 0) this.params.moneyVariance = partial.moneyVariance;
|
|
113500
116108
|
this.renderInner();
|
|
113501
116109
|
this.renderChart();
|
|
113502
116110
|
}
|
|
@@ -113747,6 +116355,31 @@ var CustomerGoalsCard = class {
|
|
|
113747
116355
|
this.toggleExpand();
|
|
113748
116356
|
});
|
|
113749
116357
|
}
|
|
116358
|
+
this.renderMoneyVariance();
|
|
116359
|
+
}
|
|
116360
|
+
/**
|
|
116361
|
+
* RFC-0228 A7 — append the R$ variance readout below the totals/deltas strip when a
|
|
116362
|
+
* money overlay/amount is present. `renderMoneyVariance` returns `null` when the gate
|
|
116363
|
+
* is off (no `params.moneyVariance`), so the card stays byte-identical to before.
|
|
116364
|
+
* Reads only money names (`monetaryProjection`/`currencyBudget`) — never the quantity
|
|
116365
|
+
* `series.budget` prop (naming bridge). Honors DEC-6 withholding inside the renderer.
|
|
116366
|
+
*/
|
|
116367
|
+
renderMoneyVariance() {
|
|
116368
|
+
const mv = this.params.moneyVariance;
|
|
116369
|
+
if (!mv) return;
|
|
116370
|
+
const el2 = renderMoneyVariance({
|
|
116371
|
+
monetaryProjection: mv.monetaryProjection,
|
|
116372
|
+
currencyBudget: mv.currencyBudget,
|
|
116373
|
+
overlay: mv.overlay,
|
|
116374
|
+
withheld: mv.withheld,
|
|
116375
|
+
label: mv.label != null ? mv.label : "Varia\xE7\xE3o vs meta (R$)",
|
|
116376
|
+
document
|
|
116377
|
+
});
|
|
116378
|
+
if (!el2) return;
|
|
116379
|
+
el2.classList.add("myio-cgc__money-variance");
|
|
116380
|
+
el2.style.padding = "6px 8px 8px";
|
|
116381
|
+
el2.style.borderTop = "1px solid var(--cgc-border)";
|
|
116382
|
+
this.el.appendChild(el2);
|
|
113750
116383
|
}
|
|
113751
116384
|
destroyChart() {
|
|
113752
116385
|
try {
|
|
@@ -131020,10 +133653,10 @@ var AlarmsNotificationsPanelView = class {
|
|
|
131020
133653
|
const renderListPanel = (group, items, sel) => {
|
|
131021
133654
|
if (items.length === 0) return '<div class="afm-empty">Nenhum item encontrado</div>';
|
|
131022
133655
|
return items.map((item) => {
|
|
131023
|
-
const
|
|
133656
|
+
const esc8 = this.esc(item);
|
|
131024
133657
|
return `<label class="afm-check-item">
|
|
131025
|
-
<input type="checkbox" class="afm-checkbox" data-group="${group}" data-value="${
|
|
131026
|
-
<span class="afm-check-label">${
|
|
133658
|
+
<input type="checkbox" class="afm-checkbox" data-group="${group}" data-value="${esc8}"${sel.has(item) ? " checked" : ""}>
|
|
133659
|
+
<span class="afm-check-label">${esc8}</span>
|
|
131027
133660
|
</label>`;
|
|
131028
133661
|
}).join("");
|
|
131029
133662
|
};
|
|
@@ -143858,7 +146491,7 @@ function exportTimelineToPDF(data, labels = {}, locale = "pt-BR", opts = {}) {
|
|
|
143858
146491
|
const docTitle = buildActivationReportTitle(deviceName, opts.customerName);
|
|
143859
146492
|
const issuedAt = formatIssuedAt(/* @__PURE__ */ new Date(), locale);
|
|
143860
146493
|
const utilization = data.totalHours > 0 ? (data.totalOnMinutes / (data.totalHours * 60) * 100).toFixed(1) : "0.0";
|
|
143861
|
-
const
|
|
146494
|
+
const esc8 = (s) => String(s).replace(/[&<>"]/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """ })[c]);
|
|
143862
146495
|
const htmlContent = `
|
|
143863
146496
|
<!DOCTYPE html>
|
|
143864
146497
|
<html lang="pt-BR">
|
|
@@ -143910,14 +146543,14 @@ function exportTimelineToPDF(data, labels = {}, locale = "pt-BR", opts = {}) {
|
|
|
143910
146543
|
<div class="brand">MyIO BAS</div>
|
|
143911
146544
|
<h1>Relat\xF3rio de Acionamentos</h1>
|
|
143912
146545
|
<div class="meta">
|
|
143913
|
-
<div><b>Dispositivo:</b> ${
|
|
146546
|
+
<div><b>Dispositivo:</b> ${esc8(deviceName)}</div>
|
|
143914
146547
|
<div><b>Per\xEDodo:</b> ${periodStart} \u2014 ${periodEnd}</div>
|
|
143915
146548
|
</div>
|
|
143916
146549
|
</div>
|
|
143917
146550
|
${customerName ? `
|
|
143918
146551
|
<div class="customer-badge">
|
|
143919
146552
|
<div class="label">Cliente</div>
|
|
143920
|
-
<div class="value">${
|
|
146553
|
+
<div class="value">${esc8(customerName)}</div>
|
|
143921
146554
|
</div>` : ""}
|
|
143922
146555
|
</div>
|
|
143923
146556
|
|
|
@@ -143928,7 +146561,7 @@ function exportTimelineToPDF(data, labels = {}, locale = "pt-BR", opts = {}) {
|
|
|
143928
146561
|
</div>
|
|
143929
146562
|
<div class="summary-card accent-green">
|
|
143930
146563
|
<div class="summary-value">${formatDurationMinutes(data.totalOnMinutes)}</div>
|
|
143931
|
-
<div class="summary-label">Tempo ${
|
|
146564
|
+
<div class="summary-label">Tempo ${esc8(labelOn)}</div>
|
|
143932
146565
|
</div>
|
|
143933
146566
|
<div class="summary-card accent-amber">
|
|
143934
146567
|
<div class="summary-value">${utilization}%</div>
|
|
@@ -143956,7 +146589,7 @@ function exportTimelineToPDF(data, labels = {}, locale = "pt-BR", opts = {}) {
|
|
|
143956
146589
|
<tr>
|
|
143957
146590
|
<td>${formatDateForExport(seg.startTime, locale)}</td>
|
|
143958
146591
|
<td>${formatDateForExport(seg.endTime, locale)}</td>
|
|
143959
|
-
<td><span class="pill ${seg.state === "on" ? "pill-on" : "pill-off"}">${seg.state === "on" ?
|
|
146592
|
+
<td><span class="pill ${seg.state === "on" ? "pill-on" : "pill-off"}">${seg.state === "on" ? esc8(labelOn) : esc8(labelOff)}</span></td>
|
|
143960
146593
|
<td>${formatDurationMinutes(seg.durationMinutes)}</td>
|
|
143961
146594
|
<td>${seg.source === "manual" ? "Manual" : seg.source === "schedule" ? "Agendamento" : seg.source === "automation" ? "Automa\xE7\xE3o" : "Desconhecido"}</td>
|
|
143962
146595
|
</tr>
|
|
@@ -143965,7 +146598,7 @@ function exportTimelineToPDF(data, labels = {}, locale = "pt-BR", opts = {}) {
|
|
|
143965
146598
|
</table>
|
|
143966
146599
|
|
|
143967
146600
|
<div class="footer">
|
|
143968
|
-
<span class="issued">Emitido em ${issuedAt}</span>${customerName ? ` · ${
|
|
146601
|
+
<span class="issued">Emitido em ${issuedAt}</span>${customerName ? ` · ${esc8(customerName)}` : ""} · <span class="brand">MyIO BAS</span>
|
|
143969
146602
|
</div>
|
|
143970
146603
|
</body>
|
|
143971
146604
|
</html>
|
|
@@ -147149,9 +149782,9 @@ function renderModalHTML2(data, config2) {
|
|
|
147149
149782
|
const subAmbientesHTML = data.subAmbientes.map((sub, index) => {
|
|
147150
149783
|
const ambData = sub.ambienteData;
|
|
147151
149784
|
const status = ambData.status || "offline";
|
|
147152
|
-
let
|
|
149785
|
+
let devicesHTML2 = "";
|
|
147153
149786
|
if (ambData.energyDevices && ambData.energyDevices.length > 0) {
|
|
147154
|
-
|
|
149787
|
+
devicesHTML2 = ambData.energyDevices.map((device) => `
|
|
147155
149788
|
<div class="${AMBIENTE_GROUP_CSS_PREFIX}__device-item">
|
|
147156
149789
|
<span class="${AMBIENTE_GROUP_CSS_PREFIX}__device-icon">${getDeviceIcon6(device.deviceProfile || device.deviceType || "")}</span>
|
|
147157
149790
|
<div class="${AMBIENTE_GROUP_CSS_PREFIX}__device-info">
|
|
@@ -147162,7 +149795,7 @@ function renderModalHTML2(data, config2) {
|
|
|
147162
149795
|
</div>
|
|
147163
149796
|
`).join("");
|
|
147164
149797
|
} else if (ambData.devices && ambData.devices.length > 0) {
|
|
147165
|
-
|
|
149798
|
+
devicesHTML2 = ambData.devices.slice(0, 6).map((device) => `
|
|
147166
149799
|
<div class="${AMBIENTE_GROUP_CSS_PREFIX}__device-item">
|
|
147167
149800
|
<span class="${AMBIENTE_GROUP_CSS_PREFIX}__device-icon">${getDeviceIcon6(device.deviceProfile || device.deviceType || "")}</span>
|
|
147168
149801
|
<div class="${AMBIENTE_GROUP_CSS_PREFIX}__device-info">
|
|
@@ -147210,7 +149843,7 @@ function renderModalHTML2(data, config2) {
|
|
|
147210
149843
|
<span class="${AMBIENTE_GROUP_CSS_PREFIX}__subambiente-arrow">\u25B6</span>
|
|
147211
149844
|
</div>
|
|
147212
149845
|
<div class="${AMBIENTE_GROUP_CSS_PREFIX}__subambiente-details">
|
|
147213
|
-
${
|
|
149846
|
+
${devicesHTML2 ? `<div class="${AMBIENTE_GROUP_CSS_PREFIX}__devices-grid">${devicesHTML2}</div>` : '<p style="color:#6c757d;font-size:13px;">Nenhum dispositivo configurado</p>'}
|
|
147214
149847
|
${remotesHTML}
|
|
147215
149848
|
</div>
|
|
147216
149849
|
</div>
|
|
@@ -156865,6 +159498,7 @@ var version = package_default.version || "0.0.0";
|
|
|
156865
159498
|
CONSUMPTION_CHART_COLORS,
|
|
156866
159499
|
CONSUMPTION_CHART_DEFAULTS,
|
|
156867
159500
|
CONSUMPTION_THEME_COLORS,
|
|
159501
|
+
COVERAGE_STYLE_ID,
|
|
156868
159502
|
CUSTOMER_CODE_RE,
|
|
156869
159503
|
CUSTOMER_NAME_STOPWORDS,
|
|
156870
159504
|
CardGridPanel,
|
|
@@ -156932,6 +159566,7 @@ var version = package_default.version || "0.0.0";
|
|
|
156932
159566
|
DEFAULT_SWITCH_STATE,
|
|
156933
159567
|
DEFAULT_TABS,
|
|
156934
159568
|
DEFAULT_WATER_GROUP_COLORS,
|
|
159569
|
+
DEVICE_CATEGORY_STYLE_ID,
|
|
156935
159570
|
DEVICE_COUNT_KEYS,
|
|
156936
159571
|
DEVICE_OPERATIONAL_CARD_GRID_STYLES,
|
|
156937
159572
|
DEVICE_OPERATIONAL_CARD_STYLES,
|
|
@@ -156943,6 +159578,7 @@ var version = package_default.version || "0.0.0";
|
|
|
156943
159578
|
DOMAIN_CODES,
|
|
156944
159579
|
DOMAIN_MAP,
|
|
156945
159580
|
DeviceCategory,
|
|
159581
|
+
DeviceCategoryConflictError,
|
|
156946
159582
|
DeviceComparisonTooltip,
|
|
156947
159583
|
DeviceContextType,
|
|
156948
159584
|
DeviceDomainType,
|
|
@@ -156990,6 +159626,8 @@ var version = package_default.version || "0.0.0";
|
|
|
156990
159626
|
GRANULARITY_SELECTOR_CSS_PREFIX,
|
|
156991
159627
|
GRID_SORT_OPTIONS,
|
|
156992
159628
|
GoalsModal,
|
|
159629
|
+
GoalsMoneyApiError,
|
|
159630
|
+
GoalsMoneyClient,
|
|
156993
159631
|
HEADER_CSS_PREFIX,
|
|
156994
159632
|
HEADER_DEFAULT_CARD_COLORS,
|
|
156995
159633
|
HEADER_DEFAULT_CONFIG_TEMPLATE,
|
|
@@ -157017,6 +159655,9 @@ var version = package_default.version || "0.0.0";
|
|
|
157017
159655
|
MEASUREMENT_DOMAIN_CONFIG,
|
|
157018
159656
|
MENU_SHOPPING_CSS_PREFIX,
|
|
157019
159657
|
METRO_TILE_COLORS,
|
|
159658
|
+
MONEY_DASH,
|
|
159659
|
+
MONEY_REQUIRES_DEVICE_GRANULARITY,
|
|
159660
|
+
MONEY_VARIANCE_HEADER,
|
|
157020
159661
|
MOTOR_SORT_OPTIONS,
|
|
157021
159662
|
MYIO_CHART_PALETTE,
|
|
157022
159663
|
MYIO_CHART_PALETTE_DARK,
|
|
@@ -157061,6 +159702,7 @@ var version = package_default.version || "0.0.0";
|
|
|
157061
159702
|
POWER_LIMITS_DEVICE_TYPES,
|
|
157062
159703
|
POWER_LIMITS_STATUS_CONFIG,
|
|
157063
159704
|
POWER_LIMITS_TELEMETRY_TYPES,
|
|
159705
|
+
REPORT_MONEY_HEADER,
|
|
157064
159706
|
SCHEDULE_HOLIDAY_CSS_PREFIX,
|
|
157065
159707
|
SCHEDULE_IR_CSS_PREFIX,
|
|
157066
159708
|
SCHEDULE_ON_OFF_CSS_PREFIX,
|
|
@@ -157102,6 +159744,9 @@ var version = package_default.version || "0.0.0";
|
|
|
157102
159744
|
TELEMETRY_INFO_WATER_CATEGORY_CONFIG,
|
|
157103
159745
|
TEMPERATURE_SORT_OPTIONS,
|
|
157104
159746
|
TEMPERATURE_UNITS,
|
|
159747
|
+
TariffApiAdapter,
|
|
159748
|
+
TariffApiClient,
|
|
159749
|
+
TariffApiError,
|
|
157105
159750
|
TelemetryGridController,
|
|
157106
159751
|
TelemetryGridView,
|
|
157107
159752
|
TempComparisonTooltip,
|
|
@@ -157109,6 +159754,10 @@ var version = package_default.version || "0.0.0";
|
|
|
157109
159754
|
TempSensorSummaryTooltip,
|
|
157110
159755
|
Temperature,
|
|
157111
159756
|
UsersSummaryTooltip,
|
|
159757
|
+
VARIANCE_LABEL_ABOVE,
|
|
159758
|
+
VARIANCE_LABEL_BELOW,
|
|
159759
|
+
VARIANCE_LABEL_ONTARGET,
|
|
159760
|
+
VARIANCE_LABEL_WITHHELD,
|
|
157112
159761
|
VirtualList,
|
|
157113
159762
|
WAITING_STATUSES,
|
|
157114
159763
|
WATER_DEVICE_CATEGORIES,
|
|
@@ -157134,15 +159783,20 @@ var version = package_default.version || "0.0.0";
|
|
|
157134
159783
|
buildAnnotationServiceOrchestrator,
|
|
157135
159784
|
buildAnnotationsCsv,
|
|
157136
159785
|
buildAnnotationsExportFilename,
|
|
159786
|
+
buildBudgetHTML,
|
|
157137
159787
|
buildByStatusFromDevices,
|
|
159788
|
+
buildCoverageHTML,
|
|
157138
159789
|
buildCoverageWarningTextPtBR,
|
|
157139
159790
|
buildDeviceGridEntityObject,
|
|
157140
159791
|
buildEquipmentCategoryDataForTooltip,
|
|
157141
159792
|
buildEquipmentCategorySummary,
|
|
159793
|
+
buildFinancialRowHTML,
|
|
157142
159794
|
buildListItemsThingsboardByUniqueDatasource,
|
|
159795
|
+
buildMoneyVarianceHTML,
|
|
157143
159796
|
buildMyioIngestionAuth,
|
|
157144
159797
|
buildTemplateExport,
|
|
157145
159798
|
buildTicketServiceOrchestrator,
|
|
159799
|
+
buildVerdictHTML,
|
|
157146
159800
|
buildWaterReportCSV,
|
|
157147
159801
|
buildWaterStoresCSV,
|
|
157148
159802
|
calcDeltaPercent,
|
|
@@ -157163,6 +159817,7 @@ var version = package_default.version || "0.0.0";
|
|
|
157163
159817
|
calculateStats,
|
|
157164
159818
|
canEditAlarmRules,
|
|
157165
159819
|
canModifyAnnotation,
|
|
159820
|
+
centsToDecimalString,
|
|
157166
159821
|
checkCustomerCodeAvailable,
|
|
157167
159822
|
clampTemperature,
|
|
157168
159823
|
classify,
|
|
@@ -157174,9 +159829,14 @@ var version = package_default.version || "0.0.0";
|
|
|
157174
159829
|
clearAllAuthCaches,
|
|
157175
159830
|
clearFreshdeskTicketsOnTB,
|
|
157176
159831
|
closeAnnotationsExportModal,
|
|
159832
|
+
collapseHoursToBands,
|
|
159833
|
+
collapseTreeToBands,
|
|
157177
159834
|
collectDeviceOverrides,
|
|
157178
159835
|
computeBaseGroupResidual,
|
|
159836
|
+
computeDeltaPct,
|
|
159837
|
+
computeMoneyVariance,
|
|
157179
159838
|
connectionStatusIcons,
|
|
159839
|
+
coveragePercentLabel,
|
|
157180
159840
|
createActionButton,
|
|
157181
159841
|
createAlarmCardElement,
|
|
157182
159842
|
createAlarmsNotificationsPanelComponent,
|
|
@@ -157189,6 +159849,7 @@ var version = package_default.version || "0.0.0";
|
|
|
157189
159849
|
createConsumption7DaysChart,
|
|
157190
159850
|
createConsumptionChartWidget,
|
|
157191
159851
|
createConsumptionModal,
|
|
159852
|
+
createCoverageDeepLink,
|
|
157192
159853
|
createCsvButton,
|
|
157193
159854
|
createCustomerCardV1,
|
|
157194
159855
|
createCustomerCardV2,
|
|
@@ -157208,16 +159869,19 @@ var version = package_default.version || "0.0.0";
|
|
|
157208
159869
|
createEnergyPanelComponent,
|
|
157209
159870
|
createErrorSpan,
|
|
157210
159871
|
createExportButton,
|
|
159872
|
+
createFakeDeviceCategoryPort,
|
|
157211
159873
|
createFancoilRemote,
|
|
157212
159874
|
createFilterModalComponent,
|
|
157213
159875
|
createFooterComponent,
|
|
157214
159876
|
createFreshdeskTicket,
|
|
157215
159877
|
createGoalsBarTooltip,
|
|
159878
|
+
createGoalsMoneyClient,
|
|
157216
159879
|
createGranularitySelector,
|
|
157217
159880
|
createGroupScheduleCard,
|
|
157218
159881
|
createHeaderComponent,
|
|
157219
159882
|
createHeaderDevicesGridComponent,
|
|
157220
159883
|
createHeaderShoppingComponent,
|
|
159884
|
+
createHttpDeviceCategoryPort,
|
|
157221
159885
|
createImgGallery,
|
|
157222
159886
|
createInputDateRangePickerInsideDIV,
|
|
157223
159887
|
createLibraryVersionChecker,
|
|
@@ -157227,6 +159891,7 @@ var version = package_default.version || "0.0.0";
|
|
|
157227
159891
|
createMenuShoppingComponent,
|
|
157228
159892
|
createModalFooter,
|
|
157229
159893
|
createModalHeader,
|
|
159894
|
+
createMoneyVarianceColumn,
|
|
157230
159895
|
createMyIOTheme,
|
|
157231
159896
|
createNewTicketWizard,
|
|
157232
159897
|
createOnOffDeviceModal,
|
|
@@ -157238,6 +159903,7 @@ var version = package_default.version || "0.0.0";
|
|
|
157238
159903
|
createPdfButton,
|
|
157239
159904
|
createPresetupGateway,
|
|
157240
159905
|
createRealTimeClock,
|
|
159906
|
+
createReportMoneyColumn,
|
|
157241
159907
|
createScheduleCard,
|
|
157242
159908
|
createScheduleHoliday,
|
|
157243
159909
|
createScheduleIR,
|
|
@@ -157247,6 +159913,8 @@ var version = package_default.version || "0.0.0";
|
|
|
157247
159913
|
createSidebarMenu,
|
|
157248
159914
|
createSolenoidControl,
|
|
157249
159915
|
createSwitchControl,
|
|
159916
|
+
createTariffApiAdapter,
|
|
159917
|
+
createTariffApiClient,
|
|
157250
159918
|
createTelemetryGridComponent,
|
|
157251
159919
|
createTelemetryGridShoppingComponent,
|
|
157252
159920
|
createTelemetryInfoShoppingComponent,
|
|
@@ -157257,6 +159925,8 @@ var version = package_default.version || "0.0.0";
|
|
|
157257
159925
|
createWidgetController,
|
|
157258
159926
|
createXlsButton,
|
|
157259
159927
|
csvEscapeAnnotation,
|
|
159928
|
+
daysInMonthYear,
|
|
159929
|
+
decimalStringToCents,
|
|
157260
159930
|
decodePayload,
|
|
157261
159931
|
decodePayloadBase64Xor,
|
|
157262
159932
|
deleteFreshdeskTicket,
|
|
@@ -157267,6 +159937,8 @@ var version = package_default.version || "0.0.0";
|
|
|
157267
159937
|
detectSuperAdminHolding,
|
|
157268
159938
|
detectSuperAdminMyio,
|
|
157269
159939
|
determineInterval,
|
|
159940
|
+
deviceCategoryLabel,
|
|
159941
|
+
deviceCategoryToPanelTerm,
|
|
157270
159942
|
deviceIconLabels,
|
|
157271
159943
|
deviceIcons,
|
|
157272
159944
|
deviceStatusIcons,
|
|
@@ -157275,6 +159947,9 @@ var version = package_default.version || "0.0.0";
|
|
|
157275
159947
|
downloadAnnotationsTextFile,
|
|
157276
159948
|
escapeAnnotationHtml,
|
|
157277
159949
|
evaluateDeviceStatus,
|
|
159950
|
+
expandBandHours,
|
|
159951
|
+
expandBandToHourBucketsByYear,
|
|
159952
|
+
expandDayToHourBuckets,
|
|
157278
159953
|
exportAnnotationsCsv,
|
|
157279
159954
|
exportAnnotationsPdf,
|
|
157280
159955
|
exportGridCsv,
|
|
@@ -157306,14 +159981,17 @@ var version = package_default.version || "0.0.0";
|
|
|
157306
159981
|
formatAllInSameUnit,
|
|
157307
159982
|
formatAllInSameWaterUnit,
|
|
157308
159983
|
formatAnnotationRelativeTime,
|
|
159984
|
+
formatBRLDelta,
|
|
157309
159985
|
formatCoverageRefPtBR,
|
|
157310
159986
|
formatDashboardPercentage,
|
|
157311
159987
|
formatDateForInput,
|
|
157312
159988
|
formatDateToYMD,
|
|
157313
159989
|
formatDateWithTimezoneOffset,
|
|
159990
|
+
formatDeltaPct,
|
|
157314
159991
|
formatDuration,
|
|
157315
159992
|
formatEnergy,
|
|
157316
159993
|
formatHours,
|
|
159994
|
+
formatMoneyBRL,
|
|
157317
159995
|
formatNumberReadable,
|
|
157318
159996
|
formatPower,
|
|
157319
159997
|
formatRelativeTime,
|
|
@@ -157402,8 +160080,10 @@ var version = package_default.version || "0.0.0";
|
|
|
157402
160080
|
injectAmbienteGroupModalStyles,
|
|
157403
160081
|
injectAmbienteModalStyles,
|
|
157404
160082
|
injectBASDashboardStyles,
|
|
160083
|
+
injectCoverageStyles,
|
|
157405
160084
|
injectCustomerCardV1Styles,
|
|
157406
160085
|
injectCustomerCardV2Styles,
|
|
160086
|
+
injectDeviceCategoryStyles,
|
|
157407
160087
|
injectDeviceGridV6Styles,
|
|
157408
160088
|
injectDeviceOperationalCardGridStyles,
|
|
157409
160089
|
injectDeviceOperationalCardStyles,
|
|
@@ -157443,6 +160123,8 @@ var version = package_default.version || "0.0.0";
|
|
|
157443
160123
|
isEquipmentDevice,
|
|
157444
160124
|
isHydrometerDevice,
|
|
157445
160125
|
isInRange,
|
|
160126
|
+
isLeapYear,
|
|
160127
|
+
isMoneyColumnConfident,
|
|
157446
160128
|
isOnOffDeviceProfile,
|
|
157447
160129
|
isSolenoidDevice,
|
|
157448
160130
|
isStoreDevice,
|
|
@@ -157463,9 +160145,12 @@ var version = package_default.version || "0.0.0";
|
|
|
157463
160145
|
metasGuideDeriveTotal,
|
|
157464
160146
|
myioExportData,
|
|
157465
160147
|
nfdNormalizeAnnotationSearch,
|
|
160148
|
+
normalizeBudgetBlock,
|
|
157466
160149
|
normalizeConnectionStatus,
|
|
157467
160150
|
normalizeDeviceOverrideId,
|
|
160151
|
+
normalizeMoneyBlock,
|
|
157468
160152
|
normalizeOnOffStatus,
|
|
160153
|
+
normalizePriceString,
|
|
157469
160154
|
normalizeProfile,
|
|
157470
160155
|
normalizeRecipients,
|
|
157471
160156
|
numbers,
|
|
@@ -157484,6 +160169,7 @@ var version = package_default.version || "0.0.0";
|
|
|
157484
160169
|
openDashboardPopupSettings,
|
|
157485
160170
|
openDashboardPopupWaterTank,
|
|
157486
160171
|
openDemandModal,
|
|
160172
|
+
openDeviceCategoryPanel,
|
|
157487
160173
|
openDeviceProfileModal,
|
|
157488
160174
|
openGCDRSyncModal,
|
|
157489
160175
|
openGenericModal,
|
|
@@ -157507,6 +160193,10 @@ var version = package_default.version || "0.0.0";
|
|
|
157507
160193
|
openUpsellModal,
|
|
157508
160194
|
openUserManagementModal,
|
|
157509
160195
|
openWelcomeModal,
|
|
160196
|
+
overlayWithholdsVerdict,
|
|
160197
|
+
panelCategoryToWire,
|
|
160198
|
+
panelDomainToWire,
|
|
160199
|
+
panelTermToDeviceCategory,
|
|
157510
160200
|
parseClassificationEntities,
|
|
157511
160201
|
parseInputDateToDate,
|
|
157512
160202
|
parseLogAnnotations,
|
|
@@ -157527,17 +160217,22 @@ var version = package_default.version || "0.0.0";
|
|
|
157527
160217
|
removeSchedulingSharedStyles,
|
|
157528
160218
|
renderAlarmCard,
|
|
157529
160219
|
renderAnnotationItemCard,
|
|
160220
|
+
renderBudgetView,
|
|
157530
160221
|
renderCardAmbienteV6,
|
|
157531
160222
|
renderCardComponentHeadOffice,
|
|
157532
160223
|
renderCardComponentV5,
|
|
157533
160224
|
renderCardComponentV6,
|
|
157534
160225
|
renderCardComponentV6Alias,
|
|
157535
160226
|
renderCardV5,
|
|
160227
|
+
renderCoverageView,
|
|
157536
160228
|
renderDashboardDowntimeList,
|
|
157537
160229
|
renderDeviceGridList,
|
|
157538
160230
|
renderDualLineChart,
|
|
160231
|
+
renderFinancialIndicators,
|
|
160232
|
+
renderGatedMoney,
|
|
157539
160233
|
renderKPICards,
|
|
157540
160234
|
renderLineChart,
|
|
160235
|
+
renderMoneyVariance,
|
|
157541
160236
|
renderOnOffTimelineChart,
|
|
157542
160237
|
renderSeverityBarChart,
|
|
157543
160238
|
renderStateDonutChart,
|
|
@@ -157545,12 +160240,17 @@ var version = package_default.version || "0.0.0";
|
|
|
157545
160240
|
renderTrendChart,
|
|
157546
160241
|
reopenFreshdeskTicket,
|
|
157547
160242
|
resolveActiveProfile,
|
|
160243
|
+
resolveBudget,
|
|
157548
160244
|
resolveCategory,
|
|
157549
160245
|
resolveClassification,
|
|
160246
|
+
resolveGoalAmount,
|
|
157550
160247
|
resolveGroup,
|
|
160248
|
+
resolveMoneyRollout,
|
|
160249
|
+
resolveMoneyRowValues,
|
|
157551
160250
|
resolvePercentDecimals,
|
|
157552
160251
|
resolveSubcategory,
|
|
157553
160252
|
resolveWithFallback,
|
|
160253
|
+
routeMoneyRender,
|
|
157554
160254
|
schedCreateDateInput,
|
|
157555
160255
|
schedCreateNumberInput,
|
|
157556
160256
|
schedCreateSelect,
|
|
@@ -157562,10 +160262,13 @@ var version = package_default.version || "0.0.0";
|
|
|
157562
160262
|
setActiveProfile,
|
|
157563
160263
|
shouldFlashIcon,
|
|
157564
160264
|
shouldVirtualizeAnnotationList,
|
|
160265
|
+
signOf,
|
|
157565
160266
|
slugifyCustomerName,
|
|
157566
160267
|
sortAnnotationGroups,
|
|
157567
160268
|
sortDeviceGridDevices,
|
|
157568
160269
|
strings,
|
|
160270
|
+
subtractDecimals,
|
|
160271
|
+
sumMoneyDecimals,
|
|
157569
160272
|
telemetryInfoFormatEnergy,
|
|
157570
160273
|
telemetryInfoFormatPercentage,
|
|
157571
160274
|
telemetryInfoFormatWater,
|
|
@@ -157583,6 +160286,8 @@ var version = package_default.version || "0.0.0";
|
|
|
157583
160286
|
validateTree,
|
|
157584
160287
|
version,
|
|
157585
160288
|
waterDeviceStatusIcons,
|
|
160289
|
+
wireCategoryToPanel,
|
|
160290
|
+
wireDomainToPanel,
|
|
157586
160291
|
writeFreshdeskSyncedAtToTB,
|
|
157587
160292
|
writeFreshdeskTicketsToTB
|
|
157588
160293
|
});
|