@levi-gemcommerce/analytics 1.0.0-dev.11 → 1.0.0-dev.13

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.
Files changed (85) hide show
  1. package/dist/esm/components/GTimePicker/GTimePicker.d.ts +17 -0
  2. package/dist/esm/components/GTimePicker/components/BaseTimePicker.d.ts +10 -0
  3. package/dist/esm/components/GTimePicker/components/CompareTimePicker.d.ts +5 -0
  4. package/dist/esm/components/GTimePicker/components/DateTimeFilterAddition.d.ts +2 -0
  5. package/dist/esm/components/GTimePicker/components/DateTimeFilterInputs.d.ts +9 -0
  6. package/dist/esm/components/GTimePicker/components/DateTimeFilters.d.ts +15 -0
  7. package/dist/esm/components/GTimePicker/components/MainTimePicker.d.ts +3 -0
  8. package/dist/esm/components/GTimePicker/components/index.d.ts +2 -0
  9. package/dist/esm/components/GTimePicker/constants/compareDateTimePicker.d.ts +12 -0
  10. package/dist/esm/components/GTimePicker/constants/datePicker.d.ts +14 -0
  11. package/dist/esm/components/GTimePicker/constants/index.d.ts +2 -0
  12. package/dist/esm/components/GTimePicker/constants/mainDataTimePicker.d.ts +14 -0
  13. package/dist/esm/components/GTimePicker/contexts/DateTimePickerProvider.d.ts +15 -0
  14. package/dist/esm/components/GTimePicker/contexts/index.d.ts +1 -0
  15. package/dist/esm/components/GTimePicker/helpers/date-range-info.d.ts +16 -0
  16. package/dist/esm/components/GTimePicker/helpers/index.d.ts +4 -0
  17. package/dist/esm/components/GTimePicker/helpers/parse-date.d.ts +24 -0
  18. package/dist/esm/components/GTimePicker/helpers/time-picker.d.ts +76 -0
  19. package/dist/esm/components/GTimePicker/helpers/version.d.ts +2 -0
  20. package/dist/esm/components/GTimePicker/hooks/index.d.ts +3 -0
  21. package/dist/esm/components/GTimePicker/hooks/useCompareDateTimePicker.d.ts +25 -0
  22. package/dist/esm/components/GTimePicker/hooks/useDateTimeFilter.d.ts +18 -0
  23. package/dist/esm/components/GTimePicker/hooks/useDateTimePicker.d.ts +30 -0
  24. package/dist/esm/components/GTimePicker/hooks/useVersionDateTimeFilters.d.ts +9 -0
  25. package/dist/esm/components/GTimePicker/index.d.ts +7 -0
  26. package/dist/esm/components/GTimePicker/types/index.d.ts +38 -0
  27. package/dist/esm/components/index.d.ts +1 -0
  28. package/dist/esm/core/gemxql/helpers/getTimeDimension.d.ts +1 -1
  29. package/dist/esm/core/gemxql/index.d.ts +0 -2
  30. package/dist/esm/core/gemxql/types/date-filter.d.ts +1 -1
  31. package/dist/esm/gemxql.js +38 -48
  32. package/dist/esm/gemxql.mjs +38 -48
  33. package/dist/esm/index.d.ts +1 -4
  34. package/dist/esm/index.js +1377 -1414
  35. package/dist/esm/index.mjs +1377 -1414
  36. package/dist/esm/shared/charts/components/GPolarisViz/utilities/getFontSize.d.ts +1 -1
  37. package/dist/esm/shared/components/GTimePicker/GTimePicker.d.ts +1 -1
  38. package/dist/esm/shared/components/GTimePicker/helpers/parse-date.d.ts +2 -2
  39. package/dist/esm/shared/components/GTimePicker/hooks/useCompareDateTimePicker.d.ts +1 -2
  40. package/dist/esm/shared/components/GTimePicker/types/index.d.ts +1 -1
  41. package/dist/esm/shared/components/index.d.ts +0 -1
  42. package/dist/esm/utils/dayjs.d.ts +10 -0
  43. package/dist/esm/utils/index.d.ts +1 -0
  44. package/dist/umd/esm/components/GTimePicker/GTimePicker.d.ts +17 -0
  45. package/dist/umd/esm/components/GTimePicker/components/BaseTimePicker.d.ts +10 -0
  46. package/dist/umd/esm/components/GTimePicker/components/CompareTimePicker.d.ts +5 -0
  47. package/dist/umd/esm/components/GTimePicker/components/DateTimeFilterAddition.d.ts +2 -0
  48. package/dist/umd/esm/components/GTimePicker/components/DateTimeFilterInputs.d.ts +9 -0
  49. package/dist/umd/esm/components/GTimePicker/components/DateTimeFilters.d.ts +15 -0
  50. package/dist/umd/esm/components/GTimePicker/components/MainTimePicker.d.ts +3 -0
  51. package/dist/umd/esm/components/GTimePicker/components/index.d.ts +2 -0
  52. package/dist/umd/esm/components/GTimePicker/constants/compareDateTimePicker.d.ts +12 -0
  53. package/dist/umd/esm/components/GTimePicker/constants/datePicker.d.ts +14 -0
  54. package/dist/umd/esm/components/GTimePicker/constants/index.d.ts +2 -0
  55. package/dist/umd/esm/components/GTimePicker/constants/mainDataTimePicker.d.ts +14 -0
  56. package/dist/umd/esm/components/GTimePicker/contexts/DateTimePickerProvider.d.ts +15 -0
  57. package/dist/umd/esm/components/GTimePicker/contexts/index.d.ts +1 -0
  58. package/dist/umd/esm/components/GTimePicker/helpers/date-range-info.d.ts +16 -0
  59. package/dist/umd/esm/components/GTimePicker/helpers/index.d.ts +4 -0
  60. package/dist/umd/esm/components/GTimePicker/helpers/parse-date.d.ts +24 -0
  61. package/dist/umd/esm/components/GTimePicker/helpers/time-picker.d.ts +76 -0
  62. package/dist/umd/esm/components/GTimePicker/helpers/version.d.ts +2 -0
  63. package/dist/umd/esm/components/GTimePicker/hooks/index.d.ts +3 -0
  64. package/dist/umd/esm/components/GTimePicker/hooks/useCompareDateTimePicker.d.ts +25 -0
  65. package/dist/umd/esm/components/GTimePicker/hooks/useDateTimeFilter.d.ts +18 -0
  66. package/dist/umd/esm/components/GTimePicker/hooks/useDateTimePicker.d.ts +30 -0
  67. package/dist/umd/esm/components/GTimePicker/hooks/useVersionDateTimeFilters.d.ts +9 -0
  68. package/dist/umd/esm/components/GTimePicker/index.d.ts +7 -0
  69. package/dist/umd/esm/components/GTimePicker/types/index.d.ts +38 -0
  70. package/dist/umd/esm/components/index.d.ts +1 -0
  71. package/dist/umd/esm/core/gemxql/helpers/getTimeDimension.d.ts +1 -1
  72. package/dist/umd/esm/core/gemxql/index.d.ts +0 -2
  73. package/dist/umd/esm/core/gemxql/types/date-filter.d.ts +1 -1
  74. package/dist/umd/esm/index.d.ts +1 -4
  75. package/dist/umd/esm/shared/charts/components/GPolarisViz/utilities/getFontSize.d.ts +1 -1
  76. package/dist/umd/esm/shared/components/GTimePicker/GTimePicker.d.ts +1 -1
  77. package/dist/umd/esm/shared/components/GTimePicker/helpers/parse-date.d.ts +2 -2
  78. package/dist/umd/esm/shared/components/GTimePicker/hooks/useCompareDateTimePicker.d.ts +1 -2
  79. package/dist/umd/esm/shared/components/GTimePicker/types/index.d.ts +1 -1
  80. package/dist/umd/esm/shared/components/index.d.ts +0 -1
  81. package/dist/umd/esm/utils/dayjs.d.ts +10 -0
  82. package/dist/umd/esm/utils/index.d.ts +1 -0
  83. package/dist/umd/gemxql.js +1 -1
  84. package/dist/umd/index.js +1 -1
  85. package/package.json +1 -1
package/dist/esm/index.js CHANGED
@@ -2,11 +2,12 @@
2
2
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
3
3
  import '@tanstack/react-query';
4
4
  import dayjs from 'dayjs';
5
+ export { default as dayjs } from 'dayjs';
5
6
  import quarterOfYear from 'dayjs/plugin/quarterOfYear.js';
6
7
  import timezone from 'dayjs/plugin/timezone.js';
7
8
  import utc from 'dayjs/plugin/utc.js';
8
9
  import React, { useMemo, useCallback, useState, useEffect, forwardRef, Fragment as Fragment$1, useRef, useImperativeHandle, createContext, useContext } from 'react';
9
- import { Text, Box, InlineStack, Icon, InlineGrid, Tooltip, Button, BlockStack, Checkbox, RadioButton, Popover, ActionList, Link, SkeletonDisplayText, List, TextField, Collapsible, useBreakpoints, Select, Scrollable, OptionList, DatePicker, ButtonGroup, Card, SkeletonBodyText } from '@shopify/polaris';
10
+ import { Text, Box, InlineStack, Icon, InlineGrid, Tooltip, Button, BlockStack, Checkbox, RadioButton, Popover, ActionList, Link, SkeletonDisplayText, List, Card, SkeletonBodyText, TextField, Collapsible, useBreakpoints, Select, Scrollable, OptionList, DatePicker, ButtonGroup } from '@shopify/polaris';
10
11
  import { useTranslation } from 'react-i18next';
11
12
  import { PolarisVizProvider, LineChart, DonutChart } from '@shopify/polaris-viz';
12
13
 
@@ -348,30 +349,6 @@ EGroupOperator.OR;
348
349
  },
349
350
  ];
350
351
 
351
- dayjs.extend(utc);
352
- dayjs.extend(timezone);
353
- dayjs.extend(quarterOfYear);
354
- let tz = 'UTC';
355
- const DEFAULT_DATE_FORMAT = 'YYYY-MM-DD HH:mm:ss';
356
- const dayjsTz = (date) => {
357
- if (!date)
358
- return dayjs().tz(tz);
359
- return dayjs(date).tz(tz);
360
- };
361
- const convertDateToTz = (date) => {
362
- if (!date)
363
- return dayjs.tz(dayjs().format(DEFAULT_DATE_FORMAT), tz);
364
- return dayjs.tz(dayjs(date).format(DEFAULT_DATE_FORMAT), tz);
365
- };
366
- const dayjsTzToLocalTZ = (date) => {
367
- if (!date)
368
- return dayjs(dayjsTz().format(DEFAULT_DATE_FORMAT));
369
- return dayjs(dayjsTz(date).format(DEFAULT_DATE_FORMAT));
370
- };
371
- const dayjsTzToDate = (date) => {
372
- return dayjsTzToLocalTZ(date).toDate();
373
- };
374
-
375
352
  const TRIM_DECIMAL_ZEROS_REGEX = /\.0+$/;
376
353
  const DEFAULT_DECIMALS = 2;
377
354
  const trimDecimalZeros = (number) => {
@@ -419,6 +396,118 @@ const formatPercentage = (percentage, decimals = DEFAULT_DECIMALS) => {
419
396
  return `${cleanDecimal(percentage, decimals)}%`;
420
397
  };
421
398
 
399
+ function toVal(mix) {
400
+ if (typeof mix === 'string') {
401
+ return mix;
402
+ }
403
+ else if (typeof mix === 'object' && mix !== null) {
404
+ return Object.keys(mix)
405
+ .filter((key) => mix[key])
406
+ .join(' ');
407
+ }
408
+ else {
409
+ return false;
410
+ }
411
+ }
412
+ function cls(...classes) {
413
+ return classes.map(toVal).filter(Boolean).join(' ');
414
+ }
415
+
416
+ function compareValues(a, b, order = 'asc') {
417
+ if (a === b)
418
+ return 0;
419
+ if (a === undefined || b === undefined) {
420
+ if (a === undefined && b !== undefined)
421
+ return order === 'asc' ? -1 : 1;
422
+ if (b === undefined && a !== undefined)
423
+ return order === 'asc' ? 1 : -1;
424
+ return 0;
425
+ }
426
+ const isDate = (val) => typeof val !== 'boolean' && !isNaN(Date.parse(val));
427
+ const isString = (val) => typeof val === 'string';
428
+ let comparison = 0;
429
+ if (isDate(a) && isDate(b)) {
430
+ const dateA = a instanceof Date ? a : new Date(a);
431
+ const dateB = b instanceof Date ? b : new Date(b);
432
+ comparison = dateA > dateB ? 1 : -1;
433
+ }
434
+ else if (isString(a) && isString(b)) {
435
+ comparison = a > b ? 1 : -1;
436
+ }
437
+ else {
438
+ comparison = a > b ? 1 : -1;
439
+ }
440
+ return order === 'asc' ? -comparison : comparison;
441
+ }
442
+ function getNestedValue(obj, path) {
443
+ if (typeof path === 'string') {
444
+ return path
445
+ .replace(/\[(\d+)\]/g, '.$1')
446
+ .split('.')
447
+ .reduce((acc, key) => acc?.[key], obj);
448
+ }
449
+ return obj[path];
450
+ }
451
+ function sortByCondition(array, options) {
452
+ const { attr, order = 'asc', preferredValue, backupAttr, orderArrayAttr, orderArray } = options;
453
+ return array.slice().sort((a, b) => {
454
+ const valueA = getNestedValue(a, attr);
455
+ const valueB = getNestedValue(b, attr);
456
+ if (preferredValue !== undefined) {
457
+ if (valueA === preferredValue && valueB !== preferredValue)
458
+ return -1;
459
+ if (valueB === preferredValue && valueA !== preferredValue)
460
+ return 1;
461
+ }
462
+ if (orderArrayAttr === attr && orderArray) {
463
+ const orderArrayValue = orderArray[order];
464
+ return orderArrayValue.indexOf(valueA) - orderArrayValue.indexOf(valueB);
465
+ }
466
+ const primaryComparison = compareValues(valueA, valueB, order);
467
+ if (primaryComparison !== 0)
468
+ return primaryComparison;
469
+ if (backupAttr)
470
+ return compareValues(a[backupAttr], b[backupAttr], order);
471
+ return 0;
472
+ });
473
+ }
474
+ function sortByConditions(array, optionsArray) {
475
+ return optionsArray.reduce((sortedArray, options) => {
476
+ return sortByCondition(sortedArray, options);
477
+ }, array.slice());
478
+ }
479
+
480
+ dayjs.extend(utc);
481
+ dayjs.extend(timezone);
482
+ dayjs.extend(quarterOfYear);
483
+ let tz = 'UTC';
484
+ const DEFAULT_DATE_FORMAT = 'YYYY-MM-DD HH:mm:ss';
485
+ function getInitialTimezone() {
486
+ return tz;
487
+ }
488
+ function setTz(value) {
489
+ tz = value;
490
+ dayjs.tz.setDefault(value);
491
+ }
492
+ const dayjsTz = (date) => {
493
+ if (!date)
494
+ return dayjs().tz(tz);
495
+ return dayjs(date).tz(tz);
496
+ };
497
+ const convertDateToTz = (date) => {
498
+ if (!date)
499
+ return dayjs.tz(dayjs().format(DEFAULT_DATE_FORMAT), tz);
500
+ return dayjs.tz(dayjs(date).format(DEFAULT_DATE_FORMAT), tz);
501
+ };
502
+ const dayjsTzToLocalTZ = (date) => {
503
+ if (!date)
504
+ return dayjs(dayjsTz().format(DEFAULT_DATE_FORMAT));
505
+ return dayjs(dayjsTz(date).format(DEFAULT_DATE_FORMAT));
506
+ };
507
+ const dayjsTzToDate = (date) => {
508
+ return dayjsTzToLocalTZ(date).toDate();
509
+ };
510
+
422
511
  var AnalyticInterval;
423
512
  (function (AnalyticInterval) {
424
513
  AnalyticInterval["DAY"] = "DAY";
@@ -622,16 +711,16 @@ var GPaginationDirection;
622
711
  GPaginationDirection["PREV"] = "PREV";
623
712
  })(GPaginationDirection || (GPaginationDirection = {}));
624
713
 
625
- const TARGET_VISITOR = [
714
+ [
626
715
  { value: EVisitorType.NEW, label: 'New' },
627
716
  { value: EVisitorType.RETURNING, label: 'Returning' },
628
717
  ];
629
- const TARGET_DEVICES = [
718
+ [
630
719
  { value: EDeviceType.DESKTOP, label: 'Desktop' },
631
720
  { value: EDeviceType.TABLET, label: 'Tablet' },
632
721
  { value: EDeviceType.MOBILE, label: 'Mobile' },
633
722
  ];
634
- const TARGET_CHANNEL = [
723
+ [
635
724
  { value: ETrafficSourceType.DIRECT, label: 'Direct' },
636
725
  { value: ETrafficSourceType.EMAIL, label: 'Email' },
637
726
  { value: ETrafficSourceType.REFERRAL, label: 'Referral' },
@@ -642,11 +731,6 @@ const TARGET_CHANNEL = [
642
731
  { value: ETrafficSourceType.SMS, label: 'SMS' },
643
732
  ];
644
733
 
645
- const CAMPAIGN_BACKGROUND_MAIN = {
646
- ORIGIN: '#2C7DFF',
647
- VARIANT: '#F34A70',
648
- };
649
-
650
734
  const DEFAULT_CURRENT_PERIOD_LABEL = 'Current';
651
735
  const DEFAULT_PREVIOUS_PERIOD_LABEL = 'Previous';
652
736
  const CHART_MIN_HEIGHT = 228;
@@ -725,87 +809,6 @@ var SvgChevronUpIcon = function SvgChevronUpIcon(props) {
725
809
  };
726
810
  SvgChevronUpIcon.displayName = "ChevronUpIcon";
727
811
 
728
- function toVal(mix) {
729
- if (typeof mix === 'string') {
730
- return mix;
731
- }
732
- else if (typeof mix === 'object' && mix !== null) {
733
- return Object.keys(mix)
734
- .filter((key) => mix[key])
735
- .join(' ');
736
- }
737
- else {
738
- return false;
739
- }
740
- }
741
- function cls(...classes) {
742
- return classes.map(toVal).filter(Boolean).join(' ');
743
- }
744
-
745
- function compareValues(a, b, order = 'asc') {
746
- if (a === b)
747
- return 0;
748
- if (a === undefined || b === undefined) {
749
- if (a === undefined && b !== undefined)
750
- return order === 'asc' ? -1 : 1;
751
- if (b === undefined && a !== undefined)
752
- return order === 'asc' ? 1 : -1;
753
- return 0;
754
- }
755
- const isDate = (val) => typeof val !== 'boolean' && !isNaN(Date.parse(val));
756
- const isString = (val) => typeof val === 'string';
757
- let comparison = 0;
758
- if (isDate(a) && isDate(b)) {
759
- const dateA = a instanceof Date ? a : new Date(a);
760
- const dateB = b instanceof Date ? b : new Date(b);
761
- comparison = dateA > dateB ? 1 : -1;
762
- }
763
- else if (isString(a) && isString(b)) {
764
- comparison = a > b ? 1 : -1;
765
- }
766
- else {
767
- comparison = a > b ? 1 : -1;
768
- }
769
- return order === 'asc' ? -comparison : comparison;
770
- }
771
- function getNestedValue(obj, path) {
772
- if (typeof path === 'string') {
773
- return path
774
- .replace(/\[(\d+)\]/g, '.$1')
775
- .split('.')
776
- .reduce((acc, key) => acc?.[key], obj);
777
- }
778
- return obj[path];
779
- }
780
- function sortByCondition(array, options) {
781
- const { attr, order = 'asc', preferredValue, backupAttr, orderArrayAttr, orderArray } = options;
782
- return array.slice().sort((a, b) => {
783
- const valueA = getNestedValue(a, attr);
784
- const valueB = getNestedValue(b, attr);
785
- if (preferredValue !== undefined) {
786
- if (valueA === preferredValue && valueB !== preferredValue)
787
- return -1;
788
- if (valueB === preferredValue && valueA !== preferredValue)
789
- return 1;
790
- }
791
- if (orderArrayAttr === attr && orderArray) {
792
- const orderArrayValue = orderArray[order];
793
- return orderArrayValue.indexOf(valueA) - orderArrayValue.indexOf(valueB);
794
- }
795
- const primaryComparison = compareValues(valueA, valueB, order);
796
- if (primaryComparison !== 0)
797
- return primaryComparison;
798
- if (backupAttr)
799
- return compareValues(a[backupAttr], b[backupAttr], order);
800
- return 0;
801
- });
802
- }
803
- function sortByConditions(array, optionsArray) {
804
- return optionsArray.reduce((sortedArray, options) => {
805
- return sortByCondition(sortedArray, options);
806
- }, array.slice());
807
- }
808
-
809
812
  const GClickable = ({ children, fullWidth = false, cursor = 'pointer', onClick, onMouseEnter, onMouseLeave, }) => {
810
813
  return (jsx("div", { role: "button", tabIndex: 0, className: cls({
811
814
  'w-full': fullWidth,
@@ -1158,1410 +1161,1370 @@ const GTooltipCard = forwardRef((props, ref) => {
1158
1161
  });
1159
1162
  GTooltipCard.displayName = 'GTooltipCard';
1160
1163
 
1161
- var MainDateTimePickerAlias;
1162
- (function (MainDateTimePickerAlias) {
1163
- MainDateTimePickerAlias["TODAY"] = "today";
1164
- MainDateTimePickerAlias["YESTERDAY"] = "yesterday";
1165
- MainDateTimePickerAlias["LAST_7_DAYS"] = "last7days";
1166
- MainDateTimePickerAlias["LAST_30_DAYS"] = "last30days";
1167
- MainDateTimePickerAlias["LAST_90_DAYS"] = "last90days";
1168
- MainDateTimePickerAlias["LAST_365_DAYS"] = "last365days";
1169
- MainDateTimePickerAlias["LAST_MONTH"] = "lastMonth";
1170
- MainDateTimePickerAlias["LAST_12_MONTHS"] = "last12Months";
1171
- MainDateTimePickerAlias["LAST_YEAR"] = "lastYear";
1172
- })(MainDateTimePickerAlias || (MainDateTimePickerAlias = {}));
1173
- function getDateTimeFilterMapping() {
1174
- const mappings = {
1175
- [MainDateTimePickerAlias.TODAY]: {
1176
- title: 'Today',
1177
- alias: MainDateTimePickerAlias.TODAY,
1178
- getDateRange: getToday,
1179
- },
1180
- [MainDateTimePickerAlias.YESTERDAY]: {
1181
- title: 'Yesterday',
1182
- alias: MainDateTimePickerAlias.YESTERDAY,
1183
- getDateRange: getYesterday,
1184
- },
1185
- [MainDateTimePickerAlias.LAST_7_DAYS]: {
1186
- title: 'Last 7 days',
1187
- alias: MainDateTimePickerAlias.LAST_7_DAYS,
1188
- getDateRange: getLast7Days,
1189
- },
1190
- [MainDateTimePickerAlias.LAST_30_DAYS]: {
1191
- title: 'Last 30 days',
1192
- alias: MainDateTimePickerAlias.LAST_30_DAYS,
1193
- getDateRange: getLast30Days,
1194
- },
1195
- [MainDateTimePickerAlias.LAST_90_DAYS]: {
1196
- title: 'Last 90 days',
1197
- alias: MainDateTimePickerAlias.LAST_90_DAYS,
1198
- getDateRange: getLast90Days,
1199
- },
1200
- [MainDateTimePickerAlias.LAST_365_DAYS]: {
1201
- title: 'Last 365 days',
1202
- alias: MainDateTimePickerAlias.LAST_365_DAYS,
1203
- getDateRange: getLast365Days,
1204
- },
1205
- [MainDateTimePickerAlias.LAST_MONTH]: {
1206
- title: 'Last month',
1207
- alias: MainDateTimePickerAlias.LAST_MONTH,
1208
- getDateRange: getLastMonth,
1209
- },
1210
- [MainDateTimePickerAlias.LAST_12_MONTHS]: {
1211
- title: 'Last 12 months',
1212
- alias: MainDateTimePickerAlias.LAST_12_MONTHS,
1213
- getDateRange: getLast12Months,
1214
- },
1215
- [MainDateTimePickerAlias.LAST_YEAR]: {
1216
- title: 'Last year',
1217
- alias: MainDateTimePickerAlias.LAST_YEAR,
1218
- getDateRange: getLastYear,
1219
- },
1164
+ const GViewBySelector = ({ activatorText, selected, options, minWidth, maxWidth, preferredAlignment = 'right', onSelect, }) => {
1165
+ const [popoverActive, setPopoverActive] = useState(false);
1166
+ const [itemHover, setItemHover] = useState(null);
1167
+ const togglePopoverActive = () => setPopoverActive((prev) => !prev);
1168
+ const selectedOption = useMemo(() => {
1169
+ return options.find((item) => item.id === selected);
1170
+ }, [options, selected]);
1171
+ const activatorContent = useMemo(() => {
1172
+ if (selectedOption) {
1173
+ const content = selectedOption.title ?? selectedOption.content;
1174
+ return activatorText ? `${activatorText}: ${content}` : content;
1175
+ }
1176
+ return activatorText;
1177
+ }, [selectedOption, activatorText]);
1178
+ const handleSelect = (value) => {
1179
+ onSelect(value);
1180
+ setPopoverActive(false);
1220
1181
  };
1221
- return mappings;
1222
- }
1223
- function getDateTimeFilterByAlias(alias) {
1224
- const mappings = getDateTimeFilterMapping();
1225
- return mappings[alias];
1226
- }
1227
-
1228
- const DATE_FORMAT = {
1229
- YMD: 'YYYY-MM-DD', // 2025-01-01
1230
- MONTH_YEAR: 'MMM YYYY', // Jan 2025
1231
- FULL: 'MMMM D, YYYY', // January 1, 2025
1232
- FULL_WITH_TIME: 'MMMM D, YYYY [at] h:mm A', // January 1, 2025 at 12:00 AM
1233
- SHORT: 'MMM DD, YYYY', // Jan 01, 2025
1234
- SHORT_NO_PAD: 'MMM D, YYYY', // Jan 1, 2025
1235
- SHORT_WITH_TIME: 'MMM D, YYYY [at] h:mm A', // Jan 1, 2025 at 12:00 AM
1236
- MONTH_DAY: 'MMM D', // Jan 1
1237
- DAY_YEAR: 'D, YYYY', // 1, 2025
1238
- TIME: 'h:mm A', // 12:00 AM
1239
- MONTH_DAY_WITH_TIME: 'MMM D [at] h:mm A', // Jan 1 at 12:00 AM
1240
- YEAR: 'YYYY', // 2025
1182
+ return (jsx(Popover, { active: popoverActive, activator: jsx(GActivatorPopover, { active: popoverActive, content: activatorContent, textProps: { variant: 'bodySm' }, onClick: togglePopoverActive }), autofocusTarget: "first-node", fluidContent: true, onClose: togglePopoverActive, preferredAlignment: preferredAlignment, children: jsx(Box, { maxWidth: maxWidth, minWidth: minWidth, padding: "200", children: jsx(BlockStack, { gap: "200", children: options.map((option) => {
1183
+ const isSelected = option.id === selected;
1184
+ const isHover = itemHover === option.id;
1185
+ const borderColor = isSelected ? 'input-border' : isHover ? 'border-hover' : 'transparent';
1186
+ return (jsx(Box, { padding: "150", borderWidth: "025", borderColor: borderColor, borderRadius: "100", children: jsx("div", { onClick: () => handleSelect(option.id), className: "cursor-pointer", onMouseEnter: () => setItemHover(option.id), onMouseLeave: () => setItemHover(null), children: jsxs(InlineStack, { gap: "300", align: "space-between", blockAlign: "center", wrap: false, children: [jsxs(InlineStack, { gap: "300", blockAlign: "center", wrap: false, children: [jsx("div", { className: "bg-surface-secondary flex items-center justify-center rounded-md min-w-[184px] h-[92px]", children: jsx("img", { src: option.icon, alt: option.content, className: "w-full h-full object-contain" }) }), jsxs(BlockStack, { gap: "100", children: [jsx(Text, { as: "span", variant: "bodyMd", fontWeight: "semibold", children: option.content }), jsx(Text, { as: "p", variant: "bodyMd", tone: "subdued", children: option.helpText })] })] }), isSelected && (jsx(Box, { children: jsx(Icon, { source: SvgCheckIcon }) }))] }) }) }, option.id));
1187
+ }) }) }) }));
1241
1188
  };
1242
1189
 
1243
- function parseYearMonthDayDateString(input) {
1244
- // Date-only strings (e.g. "1970-01-01") are treated as UTC, not local time
1245
- // when using new Date()
1246
- // We need to split year, month, day to pass into new Date() separately
1247
- // to get a localized Date
1248
- return dayjs(input).valueOf();
1249
- }
1250
- const VALID_YYYY_MM_DD_DATE_REGEX = /^\d{4}-\d{1,2}-\d{1,2}/;
1251
- function isDate(date) {
1252
- return !isNaN(new Date(date).getDate());
1253
- }
1254
- function isValidYearMonthDayDateString(date) {
1255
- return VALID_YYYY_MM_DD_DATE_REGEX.test(date) && isDate(date);
1256
- }
1257
- function isValidDate(date) {
1258
- return date.length === 10 && isValidYearMonthDayDateString(date);
1259
- }
1260
- function formatDate(timestamp, type) {
1261
- const date = convertDateToTz(timestamp);
1262
- if (type === 'YMD') {
1263
- return date.format(DATE_FORMAT.YMD);
1264
- }
1265
- if (type === 'MY') {
1266
- return date.format(DATE_FORMAT.MONTH_YEAR);
1267
- }
1268
- if (type === 'FULL') {
1269
- return date.format(DATE_FORMAT.FULL);
1270
- }
1271
- if (type === 'FULL_WITH_TIME') {
1272
- return date.format(DATE_FORMAT.FULL_WITH_TIME);
1273
- }
1274
- return date.format(DATE_FORMAT.SHORT);
1275
- }
1276
- function formatTime(timestamp) {
1277
- const date = convertDateToTz(timestamp);
1278
- return date.format(DATE_FORMAT.TIME);
1279
- }
1280
- function isSameDayTimestamp(since, until) {
1281
- const sinceDate = convertDateToTz(since);
1282
- const untilDate = convertDateToTz(until);
1283
- return sinceDate.isSame(untilDate, 'day');
1284
- }
1285
- function formatTimeRange(data) {
1286
- const { since, until, format = DATE_FORMAT.TIME, showNow = false } = data;
1287
- const sinceDate = convertDateToTz(since);
1288
- const untilDate = convertDateToTz(until);
1289
- return `${sinceDate.format(format)} - ${showNow ? 'Now' : untilDate.format(format)}`;
1290
- }
1291
- function formatDateTimeRange(data) {
1292
- const { since, until, isShowNow } = data;
1293
- const sinceDate = convertDateToTz(since);
1294
- const untilDate = convertDateToTz(until);
1295
- const isToday = sinceDate.isSame(dayjsTz(), 'day');
1296
- const startTime = sinceDate.format(DATE_FORMAT.TIME);
1297
- const endTime = untilDate.format(DATE_FORMAT.TIME);
1298
- if (isToday) {
1299
- const formatEndTime = isShowNow ? 'Now' : endTime;
1300
- return `Today at ${startTime} - ${formatEndTime}`;
1301
- }
1302
- if (isShowNow) {
1303
- return `${sinceDate.format(DATE_FORMAT.SHORT_WITH_TIME)} - Now`;
1304
- }
1305
- if (sinceDate.isSame(untilDate, 'day')) {
1306
- return `${sinceDate.format(DATE_FORMAT.SHORT_WITH_TIME)} - ${endTime}`;
1307
- }
1308
- if (sinceDate.isSame(untilDate, 'day')) {
1309
- const time = formatTimeRange({ since, until });
1310
- return `${sinceDate.format(DATE_FORMAT.SHORT)} (${time})`;
1311
- }
1312
- if (sinceDate.isSame(untilDate, 'year')) {
1313
- return `${sinceDate.format(DATE_FORMAT.MONTH_DAY_WITH_TIME)} - ${untilDate.format(DATE_FORMAT.MONTH_DAY_WITH_TIME)}, ${untilDate.format(DATE_FORMAT.YEAR)}`;
1314
- }
1315
- return `${sinceDate.format(DATE_FORMAT.SHORT_WITH_TIME)} - ${untilDate.format(DATE_FORMAT.SHORT_WITH_TIME)}`;
1316
- }
1317
- const formatDayjs = (date, isEndDay = false, formatTemplate) => {
1318
- // const isUTC = date.isUTC?.() ?? false;
1319
- // if (isUTC) return date.format();
1320
- if (isEndDay && isMidnight(date)) {
1321
- return date.endOf('day').format(formatTemplate);
1322
- }
1323
- return date.format(formatTemplate);
1190
+ const ChoiceHelpText = ({ item }) => {
1191
+ return (jsxs(Text, { as: "p", variant: "bodyMd", children: [item.description, item.inlineAction && (jsx(Link, { monochrome: true, onClick: () => {
1192
+ if (item.inlineAction?.onAction) {
1193
+ item.inlineAction?.onAction();
1194
+ }
1195
+ else {
1196
+ window.open(item.inlineAction?.url, item.inlineAction?.target ?? '_blank');
1197
+ }
1198
+ }, children: item.inlineAction?.content }))] }));
1324
1199
  };
1325
- const getEndOfDayBy = (value, formatTemplate) => {
1326
- if (!value) {
1327
- return formatDayjs(dayjsTz().endOf('day'), false, formatTemplate);
1328
- }
1329
- return formatDayjs(dayjsTz(value).endOf('day'), false, formatTemplate);
1200
+
1201
+ const GChartSkeleton = () => {
1202
+ return jsx(GSkeletonDisplayText, { height: "188px" });
1330
1203
  };
1331
- const isMidnight = (date) => {
1332
- return date.hour() === 0 && date.minute() === 0;
1204
+
1205
+ const LINE_SERIES_COLORS = {
1206
+ comparison: SERIES_COLORS.comparison,
1207
+ single: SERIES_COLORS.current,
1208
+ all: [...SERIES_COLORS.all],
1333
1209
  };
1334
- const formatMs = (ms) => {
1335
- const totalSeconds = Math.floor(ms / 1000);
1336
- const hours = Math.floor(totalSeconds / 3600);
1337
- const minutes = Math.floor((totalSeconds % 3600) / 60);
1338
- const seconds = totalSeconds % 60;
1339
- return [hours, minutes, seconds].map((v) => String(v).padStart(2, '0')).join(':');
1210
+ const MetricChartProvider = ({ children, minHeight = CHART_MIN_HEIGHT, seriesColors = LINE_SERIES_COLORS, }) => {
1211
+ return (jsx(PolarisVizProvider, { themes: {
1212
+ Light: {
1213
+ chartContainer: {
1214
+ minHeight,
1215
+ },
1216
+ grid: {
1217
+ horizontalOverflow: true,
1218
+ verticalOverflow: true,
1219
+ horizontalMargin: 0,
1220
+ },
1221
+ seriesColors,
1222
+ },
1223
+ }, children: children }));
1340
1224
  };
1341
1225
 
1342
- function getDateRangeTitle(since, until) {
1343
- const sinceDate = convertDateToTz(since);
1344
- const untilDate = convertDateToTz(until);
1345
- if (sinceDate.isSame(untilDate, 'day')) {
1346
- return sinceDate.format(DATE_FORMAT.SHORT);
1347
- }
1348
- if (sinceDate.isSame(untilDate, 'month') && sinceDate.isSame(untilDate, 'year')) {
1349
- return `${sinceDate.format(DATE_FORMAT.MONTH_DAY)} - ${untilDate.format(DATE_FORMAT.DAY_YEAR)}`;
1350
- }
1351
- if (sinceDate.isSame(untilDate, 'year')) {
1352
- return `${sinceDate.format(DATE_FORMAT.MONTH_DAY)} - ${untilDate.format(DATE_FORMAT.SHORT_NO_PAD)}`;
1353
- }
1354
- return `${sinceDate.format(DATE_FORMAT.SHORT_NO_PAD)} - ${untilDate.format(DATE_FORMAT.SHORT_NO_PAD)}`;
1355
- }
1356
1226
  /**
1357
- * Resolves a { title, alias } pair from a since/until date range.
1358
- * Matches against known presets (today, last 7 days, …); falls back to
1359
- * a formatted custom range with alias "custom".
1227
+ * Returns a stateful value, and a set of memoized functions to toggle it,
1228
+ * set it to true and set it to false
1360
1229
  */
1361
- function getDateTimeFilterBase(since, until) {
1362
- const now = dayjsTz();
1363
- const sinceDate = convertDateToTz(since);
1364
- const untilDate = convertDateToTz(until);
1365
- const mappings = getDateTimeFilterMapping();
1366
- for (const mapping of Object.values(mappings)) {
1367
- const range = mapping.getDateRange(now);
1368
- const expectedSince = convertDateToTz(range.since);
1369
- const expectedUntil = convertDateToTz(range.until);
1370
- const isSameSince = sinceDate.isSame(expectedSince, 'day');
1371
- const isSameUntil = untilDate.isSame(expectedUntil, 'day');
1372
- if (isSameSince && isSameUntil) {
1373
- return { title: mapping.title, alias: mapping.alias };
1374
- }
1375
- }
1230
+ function useToggle(initialState) {
1231
+ const [value, setState] = useState(initialState);
1376
1232
  return {
1377
- title: getDateRangeTitle(since, until),
1378
- alias: 'custom',
1233
+ value,
1234
+ toggle: useCallback(() => setState((state) => !state), []),
1235
+ setTrue: useCallback(() => setState(true), []),
1236
+ setFalse: useCallback(() => setState(false), []),
1379
1237
  };
1380
1238
  }
1381
- function getVersionDateRangeTitle(data) {
1382
- const { since, until, isShowNow } = data;
1383
- const sinceDate = convertDateToTz(since);
1384
- const isToday = sinceDate.isSame(dayjsTz(), 'day');
1385
- if (isToday)
1386
- return getDateTimeFilterByAlias(MainDateTimePickerAlias.TODAY).title;
1387
- if (isShowNow)
1388
- return `${sinceDate.format(DATE_FORMAT.SHORT_NO_PAD)} - Now`;
1389
- return getDateRangeTitle(since, until);
1390
- }
1391
- const getVersionDateDescription = ({ since, until, isShowNow }) => {
1392
- const isSameDay = isSameDayTimestamp(since, until);
1393
- if (!isSameDay)
1394
- return undefined;
1395
- return formatTimeRange({ since, until, showNow: isShowNow });
1396
- };
1397
1239
 
1398
- const convertToDateTimeFilters = (versions) => {
1399
- const dataVersions = [...versions].sort((a, b) => semverToNum(b.version) - semverToNum(a.version));
1400
- return dataVersions
1401
- .map((item) => {
1402
- if (!item.startedAt)
1403
- return false;
1404
- const isCurrentVersion = !item.completedAt;
1405
- const since = dayjsTzToLocalTZ(item.startedAt).valueOf();
1406
- const until = isCurrentVersion
1407
- ? dayjsTzToLocalTZ(getEndOfDayBy()).valueOf()
1408
- : dayjsTzToLocalTZ(item.completedAt).valueOf();
1409
- const title = getVersionDateRangeTitle({ since, until, isShowNow: isCurrentVersion });
1410
- const description = getVersionDateDescription({ since, until, isShowNow: isCurrentVersion });
1240
+ const useFormatLineChartData = ({ metricKey, columnTypes }) => {
1241
+ const { formatData } = useAnalyticData();
1242
+ const formatter = metricKey ? columnTypes?.[metricKey] : undefined;
1243
+ const formatValue = (value) => {
1244
+ return String(formatData({ value, formatter }));
1245
+ };
1246
+ const yAxisOptions = {
1247
+ labelFormatter: (value) => {
1248
+ return formatValue(Number(value) || 0);
1249
+ },
1250
+ };
1251
+ return { formatValue, yAxisOptions };
1252
+ };
1253
+
1254
+ const useWindowSize = () => {
1255
+ const [windowSize, setWindowSize] = useState(() => ({
1256
+ width: typeof window !== 'undefined' ? window.innerWidth : 0,
1257
+ height: typeof window !== 'undefined' ? window.innerHeight : 0,
1258
+ }));
1259
+ const windowWidth = useMemo(() => {
1411
1260
  return {
1412
- title,
1413
- alias: `${item.version}`,
1414
- since,
1415
- until,
1416
- isVersion: true,
1417
- isCurrentVersion,
1418
- description,
1419
- versionId: item.id,
1261
+ xs: windowSize.width <= 768,
1262
+ md: 768 < windowSize.width && windowSize.width <= 1024,
1263
+ lg: windowSize.width > 1024,
1264
+ xsDown: windowSize.width < 768,
1265
+ '1200Down': windowSize.width < 1200,
1266
+ '1040Down': windowSize.width < 1040,
1420
1267
  };
1421
- })
1422
- .filter(Boolean);
1268
+ }, [windowSize.width]);
1269
+ const isMobileTabletView = !windowWidth.lg;
1270
+ const isMobileView = windowWidth.xs;
1271
+ useEffect(() => {
1272
+ const windowSizeHandler = () => {
1273
+ setWindowSize({ width: window.innerWidth, height: window.innerHeight });
1274
+ };
1275
+ window.addEventListener('resize', windowSizeHandler);
1276
+ return () => {
1277
+ window.removeEventListener('resize', windowSizeHandler);
1278
+ };
1279
+ }, []);
1280
+ return { windowSize, windowWidth, isMobileTabletView, isMobileView };
1423
1281
  };
1424
1282
 
1425
- const getNoComparison = () => {
1426
- return {
1427
- since: 0,
1428
- until: 0,
1429
- };
1430
- };
1431
- const getPreviousPeriod = (value) => {
1432
- const { since, until, alias } = value;
1433
- const sinceDate = dayjs(since);
1434
- const untilDate = dayjs(until);
1435
- if (alias === MainDateTimePickerAlias.LAST_MONTH) {
1436
- return getLastMonth(sinceDate);
1283
+ const MetricChart = ({ lineChartData, isLoading, isEmptyMetricData, columnTypes, metricKey, }) => {
1284
+ const { formatValue, yAxisOptions } = useFormatLineChartData({ metricKey, columnTypes: columnTypes || {} });
1285
+ if (!metricKey) {
1286
+ return jsx(Fragment, {});
1437
1287
  }
1438
- if (alias === MainDateTimePickerAlias.LAST_12_MONTHS) {
1439
- return getLast12Months(sinceDate);
1288
+ if (isLoading) {
1289
+ return jsx(GChartSkeleton, {});
1440
1290
  }
1441
- if (alias === MainDateTimePickerAlias.LAST_YEAR) {
1442
- return getLastYear(sinceDate);
1291
+ if (isEmptyMetricData) {
1292
+ return jsx(MetricChartEmpty, { title: "No data yet", description: "Data needs time to gather" });
1443
1293
  }
1444
- const duration = untilDate.diff(sinceDate, 'day') + 1;
1445
- const previousSince = sinceDate.subtract(duration, 'day');
1446
- const previousUntil = untilDate.subtract(duration, 'day');
1447
- return {
1448
- since: previousSince.valueOf(),
1449
- until: previousUntil.valueOf(),
1450
- };
1451
- };
1452
- const createPreviousRange = (subtractAmount, subtractUnit) => (value) => {
1453
- const { since, until } = value;
1454
- const sinceDate = dayjs(since);
1455
- const untilDate = dayjs(until);
1456
- const duration = untilDate.diff(sinceDate, 'day');
1457
- const previousSince = sinceDate.subtract(subtractAmount, subtractUnit);
1458
- const previousUntil = previousSince.add(duration, 'day');
1459
- return {
1460
- since: previousSince.valueOf(),
1461
- until: previousUntil.valueOf(),
1462
- };
1294
+ return (jsx(MetricChartProvider, { children: jsx(LineChart, { data: lineChartData, yAxisOptions: yAxisOptions, theme: "Light", tooltipOptions: {
1295
+ titleFormatter: () => `${ANALYTICS_METRIC_TOOLTIP[metricKey]?.title ?? ''}`,
1296
+ keyFormatter: (value) => {
1297
+ return value;
1298
+ },
1299
+ renderTooltipContent(data) {
1300
+ return jsx(MetricChartTooltip, { data: data, formatValue: formatValue });
1301
+ },
1302
+ }, showLegend: true }) }));
1463
1303
  };
1464
- const getPreviousWeek = createPreviousRange(7, 'day');
1465
- const getPreviousQuarter = createPreviousRange(3, 'month');
1466
- const getPreviousMonth = createPreviousRange(1, 'month');
1467
- const getPreviousYear = createPreviousRange(1, 'year');
1468
- const createLastDaysRange = (subtractAmount) => (date) => {
1469
- return {
1470
- since: date.subtract(subtractAmount, 'day').valueOf(),
1471
- until: date.valueOf(),
1472
- };
1304
+
1305
+ var IMAGE_ANALYTIC_EMPTY = "data:image/png;base64,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";
1306
+
1307
+ const MetricChartEmpty = ({ boxProps, minHeight, description, title }) => {
1308
+ return (jsx(Box, { minWidth: "100%", ...boxProps, children: jsx(GBlockCenter, { minHeight: minHeight, children: jsx(Box, { padding: '400', children: jsxs(BlockStack, { gap: "400", align: "center", inlineAlign: "center", children: [jsx("div", { className: "h-[80px] w-[80px]", children: jsx(GThumbnail, { source: IMAGE_ANALYTIC_EMPTY, width: "80px", height: "80px", alt: title, classRemoved: true }) }), jsxs(BlockStack, { gap: "200", align: "center", inlineAlign: "center", children: [jsx(Text, { as: "h4", variant: "headingSm", fontWeight: "semibold", children: title }), jsx(Text, { as: "h4", variant: "bodyMd", tone: "subdued", children: description })] })] }) }) }) }));
1473
1309
  };
1474
- const getToday = (currentDate) => {
1475
- return {
1476
- since: currentDate.valueOf(),
1477
- until: currentDate.valueOf(),
1478
- };
1310
+
1311
+ const DownIcon8px = () => {
1312
+ return (jsxs("svg", { width: "8", height: "8", viewBox: "0 0 8 8", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [jsx("g", { clipPath: "url(#clip0_18114_1160)", children: jsx("path", { d: "M1 1L6.5 6.5M6.5 6.5V1.5M6.5 6.5H1.5", stroke: "#8A8A8A", strokeWidth: "1.5" }) }), jsx("defs", { children: jsx("clipPath", { id: "clip0_18114_1160", children: jsx("rect", { width: "8", height: "8", fill: "white" }) }) })] }));
1479
1313
  };
1480
- const getYesterday = (date) => {
1481
- return {
1482
- since: date.subtract(1, 'day').valueOf(),
1483
- until: date.subtract(1, 'day').valueOf(),
1484
- };
1314
+
1315
+ const UpIcon8px = () => {
1316
+ return (jsxs("svg", { width: "8", height: "8", viewBox: "0 0 8 8", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [jsx("g", { clipPath: "url(#clip0_18114_1146)", children: jsx("path", { d: "M1 7L6.5 1.5M6.5 1.5H1.5M6.5 1.5V6.5", stroke: "#29845A", strokeWidth: "1.5" }) }), jsx("defs", { children: jsx("clipPath", { id: "clip0_18114_1146", children: jsx("rect", { width: "8", height: "8", fill: "white", transform: "matrix(0 -1 1 0 0 8)" }) }) })] }));
1485
1317
  };
1486
- const getLast7Days = createLastDaysRange(6);
1487
- const getLast30Days = createLastDaysRange(29);
1488
- const getLast90Days = createLastDaysRange(89);
1489
- const getLast365Days = createLastDaysRange(364);
1490
- function getLastMonth(date) {
1491
- return {
1492
- since: date.subtract(1, 'month').startOf('month').valueOf(),
1493
- until: date.subtract(1, 'month').endOf('month').valueOf(),
1494
- };
1495
- }
1496
- function getLast12Months(date) {
1497
- return {
1498
- since: date.subtract(12, 'month').startOf('month').valueOf(),
1499
- until: date.subtract(1, 'month').endOf('month').valueOf(),
1500
- };
1501
- }
1502
- function getLastYear(date) {
1503
- return {
1504
- since: date.subtract(1, 'year').startOf('year').valueOf(),
1505
- until: date.subtract(1, 'year').endOf('year').valueOf(),
1506
- };
1507
- }
1508
- const getMonthAndYearByDateFilter = (month, year, date) => {
1509
- const endDate = dayjs(date);
1510
- const endMonthFilter = endDate.month();
1511
- const endYearFilter = endDate.year();
1512
- if (endYearFilter !== year || endMonthFilter !== month) {
1513
- const prev = endDate.subtract(1, 'month');
1514
- return {
1515
- month: prev.month(),
1516
- year: prev.year(),
1517
- };
1318
+
1319
+ const MetricPercentage = ({ change }) => {
1320
+ if (typeof change !== 'number') {
1321
+ return jsx("div", { style: { height: '2px', width: '11px', backgroundColor: '#8A8A8A' } });
1518
1322
  }
1519
- return { month, year };
1323
+ return (jsxs("div", { style: {
1324
+ display: 'flex',
1325
+ maxHeight: '20px',
1326
+ width: 'fit-content',
1327
+ alignItems: 'center',
1328
+ gap: '4px',
1329
+ borderRadius: '8px',
1330
+ fontSize: '12px',
1331
+ color: change > 0 ? TREND_TONE.POSITIVE : TREND_TONE.NEUTRAL,
1332
+ }, children: [change < 0 && (jsx(InlineStack, { align: "center", children: jsx(DownIcon8px, {}) })), change > 0 && (jsx(InlineStack, { align: "center", children: jsx(UpIcon8px, {}) })), jsx(Text, { as: "span", variant: "bodyXs", fontWeight: "semibold", children: formatPercentage(Math.abs(change || 0)) })] }));
1520
1333
  };
1521
1334
 
1522
- var CompareDateTimePickerAlias;
1523
- (function (CompareDateTimePickerAlias) {
1524
- CompareDateTimePickerAlias["NO_COMPARISON"] = "noComparison";
1525
- CompareDateTimePickerAlias["PREVIOUS_PERIOD"] = "previousPeriod";
1526
- CompareDateTimePickerAlias["PREVIOUS_WEEK"] = "previousWeek";
1527
- CompareDateTimePickerAlias["PREVIOUS_MONTH"] = "previousMonth";
1528
- CompareDateTimePickerAlias["PREVIOUS_QUARTER"] = "previousQuarter";
1529
- CompareDateTimePickerAlias["PREVIOUS_YEAR"] = "previousYear";
1530
- })(CompareDateTimePickerAlias || (CompareDateTimePickerAlias = {}));
1531
- const PREVIOUS_PERIOD_FILTER = {
1532
- title: 'Previous period',
1533
- alias: CompareDateTimePickerAlias.PREVIOUS_PERIOD,
1534
- since: 0,
1535
- until: 0,
1335
+ const MetricChartTooltip = ({ data, formatValue }) => {
1336
+ const { activeIndex } = data;
1337
+ const currentData = data?.dataSeries[0]?.data[activeIndex];
1338
+ const previousData = data?.dataSeries[1]?.data[activeIndex];
1339
+ const formatPercent = () => {
1340
+ const value = currentData.trend?.value;
1341
+ if (!value)
1342
+ return PLACEHOLDER_VALUE;
1343
+ const valueNumber = Number(value.replace(/[%~]/g, ''));
1344
+ if (currentData.trend?.trend === 'negative') {
1345
+ return valueNumber * -1;
1346
+ }
1347
+ return valueNumber;
1348
+ };
1349
+ return (jsx("div", { className: "w-fit min-w-[175px]", children: jsx(Card, { padding: '200', children: jsxs(BlockStack, { gap: '100', children: [jsx(Text, { as: "p", variant: "bodySm", fontWeight: "semibold", children: data.formatters?.titleFormatter?.(data.title || '') || data.title }), jsxs(BlockStack, { gap: '100', children: [jsxs(InlineStack, { gap: '400', align: "space-between", blockAlign: "center", children: [jsxs(InlineStack, { gap: '100', blockAlign: "center", children: [jsx("div", { className: "h-[2px] w-[12px] rounded-[10px] bg-[#4FA9EA]" }), jsx(Text, { as: "p", variant: "bodySm", fontWeight: "medium", tone: "subdued", children: currentData.tooltipKey })] }), jsxs(InlineStack, { blockAlign: "center", gap: "100", children: [jsx(Text, { as: "span", variant: "bodySm", fontWeight: "semibold", children: formatValue(currentData.value) }), jsx(MetricPercentage, { change: formatPercent() })] })] }), jsxs(InlineStack, { gap: '400', align: "space-between", blockAlign: "center", children: [jsxs(InlineStack, { gap: '100', blockAlign: "center", children: [jsx("div", { className: "w-[12px] border border-dashed border-[#A1CAE7]" }), jsx(Text, { as: "p", variant: "bodySm", tone: "subdued", fontWeight: "medium", children: previousData.tooltipKey })] }), jsxs(InlineStack, { blockAlign: "center", gap: "100", children: [jsx(Text, { as: "span", variant: "bodySm", fontWeight: "semibold", children: formatValue(previousData.value) }), jsx("div", { className: "opacity-0", children: jsx(MetricPercentage, { change: formatPercent() }) })] })] })] })] }) }) }));
1536
1350
  };
1537
- const DATE_TIME_COMPARISON_FILTERS = [
1538
- {
1539
- title: 'No comparison',
1540
- alias: CompareDateTimePickerAlias.NO_COMPARISON,
1541
- since: 0,
1542
- until: 0,
1543
- },
1544
- PREVIOUS_PERIOD_FILTER,
1545
- {
1546
- title: 'Previous week',
1547
- alias: CompareDateTimePickerAlias.PREVIOUS_WEEK,
1548
- since: 0,
1549
- until: 0,
1550
- },
1551
- {
1552
- title: 'Previous quarter',
1553
- alias: CompareDateTimePickerAlias.PREVIOUS_QUARTER,
1554
- since: 0,
1555
- until: 0,
1556
- },
1557
- {
1558
- title: 'Previous month',
1559
- alias: CompareDateTimePickerAlias.PREVIOUS_MONTH,
1560
- since: 0,
1561
- until: 0,
1562
- },
1563
- {
1564
- title: 'Previous year',
1565
- alias: CompareDateTimePickerAlias.PREVIOUS_YEAR,
1566
- since: 0,
1567
- until: 0,
1568
- },
1569
- ];
1570
- const COMPARE_DATE_TIME_FILTERS_MAP = {
1571
- [CompareDateTimePickerAlias.NO_COMPARISON]: getNoComparison,
1572
- [CompareDateTimePickerAlias.PREVIOUS_PERIOD]: getPreviousPeriod,
1573
- [CompareDateTimePickerAlias.PREVIOUS_WEEK]: getPreviousWeek,
1574
- [CompareDateTimePickerAlias.PREVIOUS_QUARTER]: getPreviousQuarter,
1575
- [CompareDateTimePickerAlias.PREVIOUS_MONTH]: getPreviousMonth,
1576
- [CompareDateTimePickerAlias.PREVIOUS_YEAR]: getPreviousYear,
1351
+
1352
+ const MetricInfoSkeleton = ({ isShowOneLine }) => {
1353
+ if (isShowOneLine) {
1354
+ return (jsx(Box, { width: "40%", children: jsx(SkeletonBodyText, { lines: 1 }) }));
1355
+ }
1356
+ return (jsxs(BlockStack, { gap: "200", children: [jsx(Box, { width: "60%", children: jsx(SkeletonBodyText, { lines: 1 }) }), jsx(Box, { width: "40%", children: jsx(SkeletonBodyText, { lines: 1 }) })] }));
1577
1357
  };
1578
1358
 
1579
- const useDateTimeFilter = () => {
1580
- const currentDate = dayjsTzToLocalTZ().startOf('day');
1581
- const mappings = getDateTimeFilterMapping();
1582
- const TODAY_CONFIG = mappings[MainDateTimePickerAlias.TODAY];
1583
- const TODAY_DATE_RANGE = {
1584
- ...TODAY_CONFIG,
1585
- ...TODAY_CONFIG.getDateRange(currentDate),
1586
- };
1587
- const YESTERDAY_CONFIG = mappings[MainDateTimePickerAlias.YESTERDAY];
1588
- const YESTERDAY_DATE_RANGE = {
1589
- ...YESTERDAY_CONFIG,
1590
- ...YESTERDAY_CONFIG.getDateRange(currentDate),
1591
- };
1592
- const LAST_7_DAYS_CONFIG = mappings[MainDateTimePickerAlias.LAST_7_DAYS];
1593
- const LAST_7_DAYS_DATE_RANGE = {
1594
- ...LAST_7_DAYS_CONFIG,
1595
- ...LAST_7_DAYS_CONFIG.getDateRange(currentDate),
1596
- };
1597
- const LAST_30_DAYS_CONFIG = mappings[MainDateTimePickerAlias.LAST_30_DAYS];
1598
- const LAST_30_DAYS_DATE_RANGE = {
1599
- ...LAST_30_DAYS_CONFIG,
1600
- ...LAST_30_DAYS_CONFIG.getDateRange(currentDate),
1601
- };
1602
- const LAST_90_DAYS_CONFIG = mappings[MainDateTimePickerAlias.LAST_90_DAYS];
1603
- const LAST_90_DAYS_DATE_RANGE = {
1604
- ...LAST_90_DAYS_CONFIG,
1605
- ...LAST_90_DAYS_CONFIG.getDateRange(currentDate),
1606
- };
1607
- const LAST_365_DAYS_CONFIG = mappings[MainDateTimePickerAlias.LAST_365_DAYS];
1608
- const LAST_365_DAYS_DATE_RANGE = {
1609
- ...LAST_365_DAYS_CONFIG,
1610
- ...LAST_365_DAYS_CONFIG.getDateRange(currentDate),
1359
+ const MetricDonutChartSkeleton = () => {
1360
+ return (jsx(Card, { children: jsxs(BlockStack, { gap: "400", children: [jsx(MetricInfoSkeleton, { isShowOneLine: true }), jsx(GChartSkeleton, {})] }) }));
1361
+ };
1362
+
1363
+ const MetricValueSummary = ({ totalValue, hideComparison }) => (jsx(BlockStack, { gap: "200", children: jsxs(InlineStack, { blockAlign: "center", gap: "200", wrap: false, children: [jsx(InlineStack, { blockAlign: "center", gap: "200", children: jsx(Text, { as: "span", variant: "headingSm", children: totalValue.value }) }), !hideComparison && jsx(MetricPercentage, { change: totalValue.change })] }) }));
1364
+
1365
+ const MetricInfoBlock = ({ item, isHovered, isLoading, hideComparison, titleVariant = 'headingMd', titleFontWeight, onClickTitle, }) => {
1366
+ const { key, title, totalValue } = item;
1367
+ const tooltip = ANALYTICS_METRIC_TOOLTIP[key];
1368
+ if (isLoading)
1369
+ return jsx(MetricInfoSkeleton, {});
1370
+ return (jsxs(BlockStack, { gap: "200", children: [jsx("div", { className: "hover:cursor-pointer hover:text-[--p-color-text-link-hover]", onClick: (e) => {
1371
+ e?.stopPropagation();
1372
+ onClickTitle?.(key);
1373
+ }, children: jsxs(InlineStack, { wrap: false, children: [jsx(Box, { maxWidth: "100%", overflowX: "hidden", children: jsx(GTooltipCard, { tooltip: tooltip, children: jsx(Text, { as: "span", variant: titleVariant, fontWeight: titleFontWeight, truncate: true, children: title }) }) }), isHovered && (jsx("div", { className: "flex h-[20px] w-[20px] items-center", children: jsx(Icon, { source: SvgChevronRightIcon, tone: "inherit" }) }))] }) }), jsx(MetricValueSummary, { totalValue: totalValue, hideComparison: hideComparison })] }));
1374
+ };
1375
+
1376
+ const MetricChartTab = ({ item, isActive, isLoading, hideComparison, onSelect, onClickTitle, }) => {
1377
+ const [isHovered, setIsHovered] = useState(false);
1378
+ const isHighlighted = isActive || isHovered;
1379
+ return (jsx("div", { className: "w-full cursor-pointer overflow-hidden", onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), onClick: () => onSelect(item.key), children: jsx(Box, { paddingBlock: "150", paddingInline: "300", borderRadius: "200", background: isHighlighted ? 'bg-surface-active' : undefined, children: jsx(MetricInfoBlock, { item: item, isHovered: isHovered, isLoading: isLoading, hideComparison: hideComparison, titleVariant: "headingSm", titleFontWeight: "semibold", onClickTitle: onClickTitle }) }) }));
1380
+ };
1381
+
1382
+ const GSelectableMetricChartCard = ({ metricInfo, dataChart, defaultActiveTab, isLoading, isEmptyMetricData, hideComparison, currentPeriodLabel = DEFAULT_CURRENT_PERIOD_LABEL, previousPeriodLabel = DEFAULT_PREVIOUS_PERIOD_LABEL, columnTypes, }) => {
1383
+ const [activeTab, setActiveTab] = useState(defaultActiveTab);
1384
+ const lineChartData = useMemo(() => {
1385
+ const chartData = activeTab ? dataChart[activeTab] : undefined;
1386
+ if (!chartData)
1387
+ return [];
1388
+ const currentSeries = { name: currentPeriodLabel, data: chartData.current };
1389
+ if (hideComparison)
1390
+ return [currentSeries];
1391
+ return [currentSeries, { name: previousPeriodLabel, data: chartData.previous, isComparison: true }];
1392
+ }, [activeTab, dataChart, hideComparison, currentPeriodLabel, previousPeriodLabel]);
1393
+ return (jsxs(Card, { children: [jsx("div", { style: {
1394
+ display: 'grid',
1395
+ gridTemplateColumns: `repeat(${metricInfo.length}, 1fr)`,
1396
+ gap: '16px',
1397
+ marginBottom: '16px',
1398
+ }, children: metricInfo.map((item) => (jsx(MetricChartTab, { item: item, isActive: activeTab === item.key, isLoading: isLoading, hideComparison: hideComparison, onSelect: setActiveTab }, item.key))) }), jsx(MetricChart, { lineChartData: lineChartData, isLoading: isLoading, isEmptyMetricData: isEmptyMetricData, metricKey: activeTab, columnTypes: columnTypes })] }));
1399
+ };
1400
+
1401
+ const calculatePercentageChange = (current, previous) => {
1402
+ if (current === 0 && previous === 0) {
1403
+ return undefined;
1404
+ }
1405
+ if (previous === 0) {
1406
+ return current > 0 ? '100%' : '0%';
1407
+ }
1408
+ const change = ((current - previous) / previous) * 100;
1409
+ return `${Math.abs(change).toFixed(0)}%`;
1410
+ };
1411
+ const computeDonutData = ({ name, currentValue, prevValue, hasPreviousData, }) => ({
1412
+ name,
1413
+ data: [{ key: 'value', value: currentValue }],
1414
+ metadata: {
1415
+ trend: {
1416
+ value: hasPreviousData ? calculatePercentageChange(currentValue, prevValue) : undefined,
1417
+ direction: currentValue >= prevValue ? 'upward' : 'downward',
1418
+ trend: currentValue >= prevValue ? 'positive' : 'negative',
1419
+ },
1420
+ },
1421
+ });
1422
+ const getTotalCountByType = (stats, type) => {
1423
+ const item = stats?.find((stat) => stat?.type?.toLowerCase() === type.toLowerCase());
1424
+ return item?.total ?? 0;
1425
+ };
1426
+ const buildBreakdownDonutData = ({ targets, metricKey, totalsRow, comparisonTotalsRow, sort, }) => {
1427
+ const items = parseBreakdownItems(totalsRow?.[metricKey]);
1428
+ const comparisonItems = parseBreakdownItems(comparisonTotalsRow?.[metricKey]);
1429
+ const hasPreviousData = !!comparisonTotalsRow?.[metricKey];
1430
+ const result = targets.map(({ value, label }) => computeDonutData({
1431
+ name: label,
1432
+ currentValue: getTotalCountByType(items, value),
1433
+ prevValue: getTotalCountByType(comparisonItems, value),
1434
+ hasPreviousData,
1435
+ }));
1436
+ const getValue = (item) => item.data[0]?.value ?? 0;
1437
+ return sort ? [...result].sort((a, b) => getValue(b) - getValue(a)) : result;
1438
+ };
1439
+
1440
+ const DONUT_CHART_MIN_HEIGHT = 294;
1441
+ const COMPACT_MAX_WIDTH = 1500;
1442
+ const MetricDonutChartCard = ({ label, metricKey, targets, totalsRow, comparisonTotalsRow, sort, isLoading, isEmptyMetricData, minHeight = DONUT_CHART_MIN_HEIGHT, onClick, }) => {
1443
+ const tooltip = ANALYTICS_METRIC_TOOLTIP[metricKey];
1444
+ const { windowWidth, windowSize } = useWindowSize();
1445
+ const [isHovered, setIsHovered] = useState(false);
1446
+ const data = useMemo(() => buildBreakdownDonutData({ targets, metricKey, totalsRow, comparisonTotalsRow, sort }), [targets, metricKey, totalsRow, comparisonTotalsRow, sort]);
1447
+ if (isLoading) {
1448
+ return jsx(MetricDonutChartSkeleton, {});
1449
+ }
1450
+ const formatValue = (value) => {
1451
+ return numberWithCommas(`${value}`);
1611
1452
  };
1612
- const LAST_MONTH_CONFIG = mappings[MainDateTimePickerAlias.LAST_MONTH];
1613
- const LAST_MONTH_DATE_RANGE = {
1614
- ...LAST_MONTH_CONFIG,
1615
- ...LAST_MONTH_CONFIG.getDateRange(currentDate),
1453
+ const handleClickTitle = (event) => {
1454
+ event.stopPropagation();
1455
+ onClick();
1616
1456
  };
1617
- const LAST_12_MONTHS_CONFIG = mappings[MainDateTimePickerAlias.LAST_12_MONTHS];
1618
- const LAST_12_MONTHS_DATE_RANGE = {
1619
- ...LAST_12_MONTHS_CONFIG,
1620
- ...LAST_12_MONTHS_CONFIG.getDateRange(currentDate),
1457
+ const isCompactView = windowWidth.lg && windowSize.width < COMPACT_MAX_WIDTH;
1458
+ return (jsx("div", { onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), children: jsx(Card, { children: jsxs(BlockStack, { gap: "200", children: [jsx(InlineStack, { children: jsx("div", { className: "hover:cursor-pointer hover:text-[--p-color-text-link-hover]", onClick: handleClickTitle, children: jsxs(InlineStack, { children: [jsx(GTooltipCard, { tooltip: tooltip, children: jsx(Text, { as: "h3", variant: "headingMd", children: label }) }), isHovered && jsx(Icon, { source: SvgChevronRightIcon, tone: "inherit" })] }) }) }), jsx("div", { className: cls('flex items-center justify-center', {
1459
+ 'max-h-[250px] overflow-hidden': isCompactView,
1460
+ }), children: isEmptyMetricData ? (jsx(MetricChartEmpty, { title: "No data yet", description: "Data needs time to gather" })) : (jsx(MetricChartProvider, { minHeight: minHeight, seriesColors: {}, children: jsx(DonutChart, { data: data, legendPosition: "left", showLegendValues: true, showLegend: true, theme: "Light", tooltipOptions: {
1461
+ valueFormatter: formatValue,
1462
+ }, labelFormatter: formatValue }) })) })] }) }) }));
1463
+ };
1464
+
1465
+ const SingleMetricChartCard = ({ metricInfo, lineChartData, isLoading, hideComparison, columnTypes, isEmptyMetricData, onClickTitle, }) => {
1466
+ const [isHovered, setIsHovered] = useState(false);
1467
+ return (jsx("div", { onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), children: jsx(Card, { children: jsxs(BlockStack, { gap: "200", children: [jsx(MetricInfoBlock, { item: metricInfo, isHovered: isHovered, isLoading: isLoading, hideComparison: hideComparison, onClickTitle: onClickTitle }), jsx(MetricChart, { lineChartData: lineChartData, isLoading: isLoading, isEmptyMetricData: isEmptyMetricData, columnTypes: columnTypes, metricKey: metricInfo.key })] }) }) }));
1468
+ };
1469
+
1470
+ var IMAGE_FIRST_SESSION = "data:image/png;base64,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";
1471
+
1472
+ var IMAGE_ALL_SESSION = "data:image/png;base64,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";
1473
+
1474
+ var EAnalyticMode;
1475
+ (function (EAnalyticMode) {
1476
+ EAnalyticMode["ALL_SESSION"] = "ALL_SESSION";
1477
+ EAnalyticMode["FIRST_SESSION"] = "FIRST_SESSION";
1478
+ EAnalyticMode["PAGE_ONLY"] = "PAGE_ONLY";
1479
+ })(EAnalyticMode || (EAnalyticMode = {}));
1480
+
1481
+ const VIEW_BY_OPTIONS = [
1482
+ {
1483
+ id: EAnalyticMode.ALL_SESSION,
1484
+ content: 'All sessions',
1485
+ helpText: 'Count metrics for all sessions where this page shows up anywhere in the journey: before, during, or after other pages.',
1486
+ icon: IMAGE_ALL_SESSION,
1487
+ },
1488
+ {
1489
+ id: EAnalyticMode.FIRST_SESSION,
1490
+ content: 'Entry session only',
1491
+ helpText: 'Count metrics for sessions only where this page was the very first page visited, then track how they moved through the funnel.',
1492
+ icon: IMAGE_FIRST_SESSION,
1493
+ },
1494
+ ];
1495
+ const AnalyticModeSelector = ({ activatorText = 'View by', value, onChange }) => {
1496
+ const options = useMemo(() => {
1497
+ return VIEW_BY_OPTIONS.map((option) => ({
1498
+ ...option,
1499
+ }));
1500
+ }, []);
1501
+ const onSelectMode = (value) => {
1502
+ onChange(value);
1621
1503
  };
1622
- const LAST_YEAR_CONFIG = mappings[MainDateTimePickerAlias.LAST_YEAR];
1623
- const LAST_YEAR_DATE_RANGE = {
1624
- ...LAST_YEAR_CONFIG,
1625
- ...LAST_YEAR_CONFIG.getDateRange(currentDate),
1504
+ return (jsx(GViewBySelector, { activatorText: activatorText, options: options, selected: value, onSelect: onSelectMode, maxWidth: "650px" }));
1505
+ };
1506
+
1507
+ const EXCHANGE_RATE_HELP_URL = 'https://help.shopify.com/en/manual/international/pricing/exchange-rates#auto-convert';
1508
+ const CurrencySelector = ({ currencies, selected, preferredAlignment = 'left', activatorText, onSelect, }) => {
1509
+ const { t } = useTranslation();
1510
+ const onSelectRef = useRef(onSelect);
1511
+ const handleSelection = useCallback((value) => {
1512
+ onSelectRef.current?.(value);
1513
+ }, []);
1514
+ const actionItems = useMemo(() => {
1515
+ if (!currencies)
1516
+ return [];
1517
+ const formattedCurrencies = currencies.map((currency) => ({
1518
+ content: currency,
1519
+ id: currency,
1520
+ }));
1521
+ const hasCurrencyDefault = formattedCurrencies.some((item) => item.id === DEFAULT_CURRENCY_ANALYTIC);
1522
+ if (!hasCurrencyDefault) {
1523
+ formattedCurrencies.push({
1524
+ content: DEFAULT_CURRENCY_ANALYTIC,
1525
+ id: DEFAULT_CURRENCY_ANALYTIC,
1526
+ });
1527
+ }
1528
+ return sortByConditions(formattedCurrencies, [
1529
+ { attr: 'content', order: 'asc', preferredValue: DEFAULT_CURRENCY_ANALYTIC },
1530
+ ]);
1531
+ }, [currencies]);
1532
+ const actionListItems = useMemo(() => {
1533
+ return actionItems.map((option) => ({
1534
+ id: option.id,
1535
+ content: option.content,
1536
+ onAction: () => handleSelection(option.id),
1537
+ active: option.id === selected,
1538
+ suffix: option.id === selected && jsx(Icon, { source: SvgCheckIcon, tone: "success" }),
1539
+ helpText: option.id === DEFAULT_CURRENCY_ANALYTIC && (jsx(Text, { as: "p", fontWeight: "semibold", children: t('Default') })),
1540
+ }));
1541
+ }, [actionItems, selected, handleSelection, t]);
1542
+ const isHidden = useMemo(() => {
1543
+ if (!actionItems?.length)
1544
+ return true;
1545
+ return actionItems.length === 1 && actionItems[0]?.id === DEFAULT_CURRENCY_ANALYTIC;
1546
+ }, [actionItems]);
1547
+ useEffect(() => {
1548
+ onSelectRef.current = onSelect;
1549
+ });
1550
+ if (isHidden)
1551
+ return null;
1552
+ return (jsx(GSelector, { options: actionListItems, selected: selected, variant: "action-list",
1553
+ // value originates from our CurrencyCode option ids, so the widen-to-string round trip is safe
1554
+ onSelect: (value) => handleSelection(value), activatorText: activatorText ?? t('Currency'), maxWidth: "225px", preferredAlignment: preferredAlignment, helpText: jsx(Box, { padding: "200", paddingBlockStart: "300", paddingBlockEnd: "300", borderColor: "border-tertiary", background: 'bg', children: jsx(GI18NText, { as: "p", variant: "bodyMd", transformers: {
1555
+ 1: (text) => (jsx(GTextLink, { linkAction: {
1556
+ url: EXCHANGE_RATE_HELP_URL,
1557
+ target: '_blank',
1558
+ }, children: text }, text + 'text-link')),
1559
+ }, children: t("This will follow Shopify's current exchange rate. [1]Read more[]") }) }) }));
1560
+ };
1561
+
1562
+ var MainDateTimePickerAlias;
1563
+ (function (MainDateTimePickerAlias) {
1564
+ MainDateTimePickerAlias["TODAY"] = "today";
1565
+ MainDateTimePickerAlias["YESTERDAY"] = "yesterday";
1566
+ MainDateTimePickerAlias["LAST_7_DAYS"] = "last7days";
1567
+ MainDateTimePickerAlias["LAST_30_DAYS"] = "last30days";
1568
+ MainDateTimePickerAlias["LAST_90_DAYS"] = "last90days";
1569
+ MainDateTimePickerAlias["LAST_365_DAYS"] = "last365days";
1570
+ MainDateTimePickerAlias["LAST_MONTH"] = "lastMonth";
1571
+ MainDateTimePickerAlias["LAST_12_MONTHS"] = "last12Months";
1572
+ MainDateTimePickerAlias["LAST_YEAR"] = "lastYear";
1573
+ })(MainDateTimePickerAlias || (MainDateTimePickerAlias = {}));
1574
+ function getDateTimeFilterMapping() {
1575
+ const mappings = {
1576
+ [MainDateTimePickerAlias.TODAY]: {
1577
+ title: 'Today',
1578
+ alias: MainDateTimePickerAlias.TODAY,
1579
+ getDateRange: getToday,
1580
+ },
1581
+ [MainDateTimePickerAlias.YESTERDAY]: {
1582
+ title: 'Yesterday',
1583
+ alias: MainDateTimePickerAlias.YESTERDAY,
1584
+ getDateRange: getYesterday,
1585
+ },
1586
+ [MainDateTimePickerAlias.LAST_7_DAYS]: {
1587
+ title: 'Last 7 days',
1588
+ alias: MainDateTimePickerAlias.LAST_7_DAYS,
1589
+ getDateRange: getLast7Days,
1590
+ },
1591
+ [MainDateTimePickerAlias.LAST_30_DAYS]: {
1592
+ title: 'Last 30 days',
1593
+ alias: MainDateTimePickerAlias.LAST_30_DAYS,
1594
+ getDateRange: getLast30Days,
1595
+ },
1596
+ [MainDateTimePickerAlias.LAST_90_DAYS]: {
1597
+ title: 'Last 90 days',
1598
+ alias: MainDateTimePickerAlias.LAST_90_DAYS,
1599
+ getDateRange: getLast90Days,
1600
+ },
1601
+ [MainDateTimePickerAlias.LAST_365_DAYS]: {
1602
+ title: 'Last 365 days',
1603
+ alias: MainDateTimePickerAlias.LAST_365_DAYS,
1604
+ getDateRange: getLast365Days,
1605
+ },
1606
+ [MainDateTimePickerAlias.LAST_MONTH]: {
1607
+ title: 'Last month',
1608
+ alias: MainDateTimePickerAlias.LAST_MONTH,
1609
+ getDateRange: getLastMonth,
1610
+ },
1611
+ [MainDateTimePickerAlias.LAST_12_MONTHS]: {
1612
+ title: 'Last 12 months',
1613
+ alias: MainDateTimePickerAlias.LAST_12_MONTHS,
1614
+ getDateRange: getLast12Months,
1615
+ },
1616
+ [MainDateTimePickerAlias.LAST_YEAR]: {
1617
+ title: 'Last year',
1618
+ alias: MainDateTimePickerAlias.LAST_YEAR,
1619
+ getDateRange: getLastYear,
1620
+ },
1626
1621
  };
1627
- const DATE_TIME_FILTERS = [
1628
- TODAY_DATE_RANGE,
1629
- YESTERDAY_DATE_RANGE,
1630
- LAST_7_DAYS_DATE_RANGE,
1631
- LAST_30_DAYS_DATE_RANGE,
1632
- LAST_90_DAYS_DATE_RANGE,
1633
- LAST_365_DAYS_DATE_RANGE,
1634
- LAST_MONTH_DATE_RANGE,
1635
- LAST_12_MONTHS_DATE_RANGE,
1636
- LAST_YEAR_DATE_RANGE,
1637
- ];
1622
+ return mappings;
1623
+ }
1624
+ function getDateTimeFilterByAlias(alias) {
1625
+ const mappings = getDateTimeFilterMapping();
1626
+ return mappings[alias];
1627
+ }
1628
+
1629
+ const DATE_FORMAT = {
1630
+ YMD: 'YYYY-MM-DD', // 2025-01-01
1631
+ MONTH_YEAR: 'MMM YYYY', // Jan 2025
1632
+ FULL: 'MMMM D, YYYY', // January 1, 2025
1633
+ FULL_WITH_TIME: 'MMMM D, YYYY [at] h:mm A', // January 1, 2025 at 12:00 AM
1634
+ SHORT: 'MMM DD, YYYY', // Jan 01, 2025
1635
+ SHORT_NO_PAD: 'MMM D, YYYY', // Jan 1, 2025
1636
+ SHORT_WITH_TIME: 'MMM D, YYYY [at] h:mm A', // Jan 1, 2025 at 12:00 AM
1637
+ MONTH_DAY: 'MMM D', // Jan 1
1638
+ DAY_YEAR: 'D, YYYY', // 1, 2025
1639
+ TIME: 'h:mm A', // 12:00 AM
1640
+ MONTH_DAY_WITH_TIME: 'MMM D [at] h:mm A', // Jan 1 at 12:00 AM
1641
+ YEAR: 'YYYY', // 2025
1642
+ };
1643
+
1644
+ function parseYearMonthDayDateString(input) {
1645
+ // Date-only strings (e.g. "1970-01-01") are treated as UTC, not local time
1646
+ // when using new Date()
1647
+ // We need to split year, month, day to pass into new Date() separately
1648
+ // to get a localized Date
1649
+ return dayjs(input).valueOf();
1650
+ }
1651
+ const VALID_YYYY_MM_DD_DATE_REGEX = /^\d{4}-\d{1,2}-\d{1,2}/;
1652
+ function isDate(date) {
1653
+ return !isNaN(new Date(date).getDate());
1654
+ }
1655
+ function isValidYearMonthDayDateString(date) {
1656
+ return VALID_YYYY_MM_DD_DATE_REGEX.test(date) && isDate(date);
1657
+ }
1658
+ function isValidDate(date) {
1659
+ return date.length === 10 && isValidYearMonthDayDateString(date);
1660
+ }
1661
+ function formatDate(timestamp, type) {
1662
+ const date = convertDateToTz(timestamp);
1663
+ if (type === 'YMD') {
1664
+ return date.format(DATE_FORMAT.YMD);
1665
+ }
1666
+ if (type === 'MY') {
1667
+ return date.format(DATE_FORMAT.MONTH_YEAR);
1668
+ }
1669
+ if (type === 'FULL') {
1670
+ return date.format(DATE_FORMAT.FULL);
1671
+ }
1672
+ if (type === 'FULL_WITH_TIME') {
1673
+ return date.format(DATE_FORMAT.FULL_WITH_TIME);
1674
+ }
1675
+ return date.format(DATE_FORMAT.SHORT);
1676
+ }
1677
+ function formatTime(timestamp) {
1678
+ const date = convertDateToTz(timestamp);
1679
+ return date.format(DATE_FORMAT.TIME);
1680
+ }
1681
+ function isSameDayTimestamp(since, until) {
1682
+ const sinceDate = convertDateToTz(since);
1683
+ const untilDate = convertDateToTz(until);
1684
+ return sinceDate.isSame(untilDate, 'day');
1685
+ }
1686
+ function formatTimeRange(data) {
1687
+ const { since, until, format = DATE_FORMAT.TIME, showNow = false } = data;
1688
+ const sinceDate = convertDateToTz(since);
1689
+ const untilDate = convertDateToTz(until);
1690
+ return `${sinceDate.format(format)} - ${showNow ? 'Now' : untilDate.format(format)}`;
1691
+ }
1692
+ function formatDateTimeRange(data) {
1693
+ const { since, until, isShowNow } = data;
1694
+ const sinceDate = convertDateToTz(since);
1695
+ const untilDate = convertDateToTz(until);
1696
+ const isToday = sinceDate.isSame(dayjsTz(), 'day');
1697
+ const startTime = sinceDate.format(DATE_FORMAT.TIME);
1698
+ const endTime = untilDate.format(DATE_FORMAT.TIME);
1699
+ if (isToday) {
1700
+ const formatEndTime = isShowNow ? 'Now' : endTime;
1701
+ return `Today at ${startTime} - ${formatEndTime}`;
1702
+ }
1703
+ if (isShowNow) {
1704
+ return `${sinceDate.format(DATE_FORMAT.SHORT_WITH_TIME)} - Now`;
1705
+ }
1706
+ if (sinceDate.isSame(untilDate, 'day')) {
1707
+ return `${sinceDate.format(DATE_FORMAT.SHORT_WITH_TIME)} - ${endTime}`;
1708
+ }
1709
+ if (sinceDate.isSame(untilDate, 'day')) {
1710
+ const time = formatTimeRange({ since, until });
1711
+ return `${sinceDate.format(DATE_FORMAT.SHORT)} (${time})`;
1712
+ }
1713
+ if (sinceDate.isSame(untilDate, 'year')) {
1714
+ return `${sinceDate.format(DATE_FORMAT.MONTH_DAY_WITH_TIME)} - ${untilDate.format(DATE_FORMAT.MONTH_DAY_WITH_TIME)}, ${untilDate.format(DATE_FORMAT.YEAR)}`;
1715
+ }
1716
+ return `${sinceDate.format(DATE_FORMAT.SHORT_WITH_TIME)} - ${untilDate.format(DATE_FORMAT.SHORT_WITH_TIME)}`;
1717
+ }
1718
+ const formatDayjs = (date, isEndDay = false, formatTemplate) => {
1719
+ // const isUTC = date.isUTC?.() ?? false;
1720
+ // if (isUTC) return date.format();
1721
+ if (isEndDay && isMidnight(date)) {
1722
+ return date.endOf('day').format(formatTemplate);
1723
+ }
1724
+ return date.format(formatTemplate);
1725
+ };
1726
+ const getEndOfDayBy = (value, formatTemplate) => {
1727
+ if (!value) {
1728
+ return formatDayjs(dayjsTz().endOf('day'), false, formatTemplate);
1729
+ }
1730
+ return formatDayjs(dayjsTz(value).endOf('day'), false, formatTemplate);
1731
+ };
1732
+ const isMidnight = (date) => {
1733
+ return date.hour() === 0 && date.minute() === 0;
1734
+ };
1735
+ const formatMs = (ms) => {
1736
+ const totalSeconds = Math.floor(ms / 1000);
1737
+ const hours = Math.floor(totalSeconds / 3600);
1738
+ const minutes = Math.floor((totalSeconds % 3600) / 60);
1739
+ const seconds = totalSeconds % 60;
1740
+ return [hours, minutes, seconds].map((v) => String(v).padStart(2, '0')).join(':');
1741
+ };
1742
+
1743
+ function getDateRangeTitle(since, until) {
1744
+ const sinceDate = convertDateToTz(since);
1745
+ const untilDate = convertDateToTz(until);
1746
+ if (sinceDate.isSame(untilDate, 'day')) {
1747
+ return sinceDate.format(DATE_FORMAT.SHORT);
1748
+ }
1749
+ if (sinceDate.isSame(untilDate, 'month') && sinceDate.isSame(untilDate, 'year')) {
1750
+ return `${sinceDate.format(DATE_FORMAT.MONTH_DAY)} - ${untilDate.format(DATE_FORMAT.DAY_YEAR)}`;
1751
+ }
1752
+ if (sinceDate.isSame(untilDate, 'year')) {
1753
+ return `${sinceDate.format(DATE_FORMAT.MONTH_DAY)} - ${untilDate.format(DATE_FORMAT.SHORT_NO_PAD)}`;
1754
+ }
1755
+ return `${sinceDate.format(DATE_FORMAT.SHORT_NO_PAD)} - ${untilDate.format(DATE_FORMAT.SHORT_NO_PAD)}`;
1756
+ }
1757
+ /**
1758
+ * Resolves a { title, alias } pair from a since/until date range.
1759
+ * Matches against known presets (today, last 7 days, …); falls back to
1760
+ * a formatted custom range with alias "custom".
1761
+ */
1762
+ function getDateTimeFilterBase(since, until) {
1763
+ const now = dayjsTz();
1764
+ const sinceDate = convertDateToTz(since);
1765
+ const untilDate = convertDateToTz(until);
1766
+ const mappings = getDateTimeFilterMapping();
1767
+ for (const mapping of Object.values(mappings)) {
1768
+ const range = mapping.getDateRange(now);
1769
+ const expectedSince = convertDateToTz(range.since);
1770
+ const expectedUntil = convertDateToTz(range.until);
1771
+ const isSameSince = sinceDate.isSame(expectedSince, 'day');
1772
+ const isSameUntil = untilDate.isSame(expectedUntil, 'day');
1773
+ if (isSameSince && isSameUntil) {
1774
+ return { title: mapping.title, alias: mapping.alias };
1775
+ }
1776
+ }
1638
1777
  return {
1639
- DATE_TIME_FILTERS,
1640
- LAST_7_DAYS_DATE_RANGE,
1641
- LAST_30_DAYS_DATE_RANGE,
1778
+ title: getDateRangeTitle(since, until),
1779
+ alias: 'custom',
1642
1780
  };
1781
+ }
1782
+ function getVersionDateRangeTitle(data) {
1783
+ const { since, until, isShowNow } = data;
1784
+ const sinceDate = convertDateToTz(since);
1785
+ const isToday = sinceDate.isSame(dayjsTz(), 'day');
1786
+ if (isToday)
1787
+ return getDateTimeFilterByAlias(MainDateTimePickerAlias.TODAY).title;
1788
+ if (isShowNow)
1789
+ return `${sinceDate.format(DATE_FORMAT.SHORT_NO_PAD)} - Now`;
1790
+ return getDateRangeTitle(since, until);
1791
+ }
1792
+ const getVersionDateDescription = ({ since, until, isShowNow }) => {
1793
+ const isSameDay = isSameDayTimestamp(since, until);
1794
+ if (!isSameDay)
1795
+ return undefined;
1796
+ return formatTimeRange({ since, until, showNow: isShowNow });
1643
1797
  };
1644
1798
 
1645
- const DateTimePickerContext = createContext({
1646
- dateTimePicked: {
1647
- since: dayjsTz().valueOf(),
1648
- until: dayjsTz().valueOf(),
1649
- title: 'Today',
1650
- alias: 'today',
1651
- },
1652
- compareDateTimePicked: PREVIOUS_PERIOD_FILTER,
1653
- setDateTimePicked: () => { },
1654
- setCompareDateTimePicked: () => { },
1655
- resetDateVersion: () => { },
1656
- });
1657
- const DateTimePickerProvider = ({ children, initDate, initDateCompare, }) => {
1658
- const [dateTimePicked, setDateTimePicked] = useState(initDate || {
1659
- since: dayjsTz().set('hour', 0).valueOf(),
1660
- until: dayjsTz().set('hour', 0).valueOf(),
1661
- title: 'Today',
1662
- alias: 'today',
1663
- });
1664
- const { DATE_TIME_FILTERS } = useDateTimeFilter();
1665
- const getCompareDateTimePicked = useCallback((alias, source = dateTimePicked) => {
1799
+ const convertToDateTimeFilters = (versions) => {
1800
+ const dataVersions = [...versions].sort((a, b) => semverToNum(b.version) - semverToNum(a.version));
1801
+ return dataVersions
1802
+ .map((item) => {
1803
+ if (!item.startedAt)
1804
+ return false;
1805
+ const isCurrentVersion = !item.completedAt;
1806
+ const since = dayjsTzToLocalTZ(item.startedAt).valueOf();
1807
+ const until = isCurrentVersion
1808
+ ? dayjsTzToLocalTZ(getEndOfDayBy()).valueOf()
1809
+ : dayjsTzToLocalTZ(item.completedAt).valueOf();
1810
+ const title = getVersionDateRangeTitle({ since, until, isShowNow: isCurrentVersion });
1811
+ const description = getVersionDateDescription({ since, until, isShowNow: isCurrentVersion });
1666
1812
  return {
1667
- ...PREVIOUS_PERIOD_FILTER,
1668
- ...COMPARE_DATE_TIME_FILTERS_MAP[alias]({
1669
- since: source.since,
1670
- until: source.until,
1671
- alias: source.alias,
1672
- }),
1813
+ title,
1814
+ alias: `${item.version}`,
1815
+ since,
1816
+ until,
1817
+ isVersion: true,
1818
+ isCurrentVersion,
1819
+ description,
1820
+ versionId: item.id,
1673
1821
  };
1674
- }, [dateTimePicked]);
1675
- const [compareDateTimePicked, setCompareDateTimePicked] = useState(initDateCompare || getCompareDateTimePicked(CompareDateTimePickerAlias.PREVIOUS_PERIOD));
1676
- const updateCompareDateTimePicked = useCallback((source) => {
1677
- if (compareDateTimePicked.alias === 'custom' ||
1678
- compareDateTimePicked.alias === CompareDateTimePickerAlias.NO_COMPARISON)
1679
- return;
1680
- setCompareDateTimePicked(getCompareDateTimePicked(compareDateTimePicked.alias, source));
1681
- }, [compareDateTimePicked, getCompareDateTimePicked]);
1682
- const resetDateVersion = () => {
1683
- const since = dayjs(dateTimePicked.since).startOf('day').valueOf();
1684
- const until = dayjs(dateTimePicked.until).startOf('day').valueOf();
1685
- const dateFilter = DATE_TIME_FILTERS.find((filter) => filter.since === since && filter.until === until);
1686
- setDateTimePicked({
1687
- ...dateTimePicked,
1688
- isVersion: false,
1689
- versionId: undefined,
1690
- isCurrentVersion: false,
1691
- description: '',
1692
- title: dateFilter?.title || dateTimePicked.title,
1693
- alias: dateFilter?.alias || 'custom',
1694
- });
1695
- };
1696
- const onSetDateTimePicked = useCallback((value) => {
1697
- setDateTimePicked(value);
1698
- updateCompareDateTimePicked(value);
1699
- }, [updateCompareDateTimePicked]);
1700
- return (jsx(DateTimePickerContext.Provider, { value: {
1701
- dateTimePicked,
1702
- setDateTimePicked: onSetDateTimePicked,
1703
- compareDateTimePicked,
1704
- setCompareDateTimePicked,
1705
- resetDateVersion,
1706
- }, children: children }));
1707
- };
1708
- const useDateTimePickerContext = () => {
1709
- const context = useContext(DateTimePickerContext);
1710
- if (!context) {
1711
- throw new Error('useDateTimePickerContext must be used within a DateTimePickerProvider');
1712
- }
1713
- return context;
1822
+ })
1823
+ .filter(Boolean);
1714
1824
  };
1715
1825
 
1716
- const useDateTimePicker = ({ ranges, initialPicked, onApply }) => {
1717
- const { DATE_TIME_FILTERS } = useDateTimeFilter();
1718
- const allRanges = ranges || DATE_TIME_FILTERS;
1719
- const { dateTimePicked, setDateTimePicked } = useDateTimePickerContext();
1720
- const [dateRange, setDateRange] = useState(dateTimePicked);
1721
- const [{ month, year }, setDate] = useState({
1722
- month: dayjs(dateTimePicked.since).month(),
1723
- year: dayjs(dateTimePicked.since).year(),
1724
- });
1725
- useEffect(() => {
1726
- if (dateTimePicked) {
1727
- const untilDate = new Date(dateTimePicked.until);
1728
- const monthDiff = (referenceDate, newDate) => {
1729
- return newDate.month - referenceDate.month + 12 * (referenceDate.year - newDate.year);
1730
- };
1731
- monthDiff({ year, month }, {
1732
- year: untilDate.getFullYear(),
1733
- month: untilDate.getMonth(),
1734
- });
1735
- // if (monthDifference > 1 || monthDifference < 0) {
1736
- // setDate({
1737
- // month: untilDate.getMonth(),
1738
- // year: untilDate.getFullYear(),
1739
- // });
1740
- // }
1741
- }
1742
- }, [dateTimePicked, month, year]);
1743
- const onMonthChange = (month, year) => {
1744
- setDate({ month, year });
1745
- };
1746
- const onCalendarChange = (value) => {
1747
- const { start, end, alias } = value;
1748
- const customDateRange = {
1749
- alias: 'custom',
1750
- title: 'Custom',
1751
- since: start.getTime(),
1752
- until: end.getTime(),
1753
- };
1754
- const newDateRange = allRanges.find((range) => {
1755
- const isSameAlias = range.alias === alias;
1756
- const isSameUntil = range.until === end.getTime();
1757
- const isSameSince = range.since === start.getTime();
1758
- // const isSameVersionId = !!range.versionId && !!versionId && range.versionId === versionId;
1759
- const isSameTime = isSameSince && isSameUntil;
1760
- return isSameAlias || isSameTime;
1761
- });
1762
- const finalDateRange = newDateRange || initialPicked || customDateRange;
1763
- setDateRange(finalDateRange);
1764
- };
1765
- const onChange = ({ end }) => {
1766
- setDate(getMonthAndYearByDateFilter(month, year, end));
1826
+ const getNoComparison = () => {
1827
+ return {
1828
+ since: 0,
1829
+ until: 0,
1767
1830
  };
1768
- const apply = () => {
1769
- setDateTimePicked(dateRange);
1770
- onApply?.(dateRange);
1831
+ };
1832
+ const getPreviousPeriod = (value) => {
1833
+ const { since, until, alias } = value;
1834
+ const sinceDate = dayjs(since);
1835
+ const untilDate = dayjs(until);
1836
+ if (alias === MainDateTimePickerAlias.LAST_MONTH) {
1837
+ return getLastMonth(sinceDate);
1838
+ }
1839
+ if (alias === MainDateTimePickerAlias.LAST_12_MONTHS) {
1840
+ return getLast12Months(sinceDate);
1841
+ }
1842
+ if (alias === MainDateTimePickerAlias.LAST_YEAR) {
1843
+ return getLastYear(sinceDate);
1844
+ }
1845
+ const duration = untilDate.diff(sinceDate, 'day') + 1;
1846
+ const previousSince = sinceDate.subtract(duration, 'day');
1847
+ const previousUntil = untilDate.subtract(duration, 'day');
1848
+ return {
1849
+ since: previousSince.valueOf(),
1850
+ until: previousUntil.valueOf(),
1771
1851
  };
1772
- const cancel = () => {
1773
- setDateRange(dateTimePicked);
1852
+ };
1853
+ const createPreviousRange = (subtractAmount, subtractUnit) => (value) => {
1854
+ const { since, until } = value;
1855
+ const sinceDate = dayjs(since);
1856
+ const untilDate = dayjs(until);
1857
+ const duration = untilDate.diff(sinceDate, 'day');
1858
+ const previousSince = sinceDate.subtract(subtractAmount, subtractUnit);
1859
+ const previousUntil = previousSince.add(duration, 'day');
1860
+ return {
1861
+ since: previousSince.valueOf(),
1862
+ until: previousUntil.valueOf(),
1774
1863
  };
1775
- useEffect(() => {
1776
- if (dateTimePicked) {
1777
- setDateRange(dateTimePicked);
1778
- setDate({
1779
- month: dayjs(dateTimePicked.since).month(),
1780
- year: dayjs(dateTimePicked.since).year(),
1781
- });
1782
- }
1783
- }, [dateTimePicked]);
1864
+ };
1865
+ const getPreviousWeek = createPreviousRange(7, 'day');
1866
+ const getPreviousQuarter = createPreviousRange(3, 'month');
1867
+ const getPreviousMonth = createPreviousRange(1, 'month');
1868
+ const getPreviousYear = createPreviousRange(1, 'year');
1869
+ const createLastDaysRange = (subtractAmount) => (date) => {
1784
1870
  return {
1785
- month,
1786
- year,
1787
- setDate,
1788
- dateRange,
1789
- apply,
1790
- cancel,
1791
- dateTimePicked,
1792
- onChange,
1793
- onMonthChange,
1794
- onCalendarChange,
1871
+ since: date.subtract(subtractAmount, 'day').valueOf(),
1872
+ until: date.valueOf(),
1873
+ };
1874
+ };
1875
+ const getToday = (currentDate) => {
1876
+ return {
1877
+ since: currentDate.valueOf(),
1878
+ until: currentDate.valueOf(),
1795
1879
  };
1796
1880
  };
1797
-
1798
- const useVersionDateTimeFilters = (versions) => {
1799
- const { t } = useTranslation();
1800
- const rangers = useMemo(() => {
1801
- if (!versions?.length)
1802
- return [];
1803
- return convertToDateTimeFilters(versions);
1804
- }, [versions]);
1805
- const rangeAddition = {
1806
- title: t('Experiment periods'),
1807
- rangers,
1881
+ const getYesterday = (date) => {
1882
+ return {
1883
+ since: date.subtract(1, 'day').valueOf(),
1884
+ until: date.subtract(1, 'day').valueOf(),
1808
1885
  };
1809
- return { rangeAddition };
1810
1886
  };
1811
-
1812
- function DateTimeFilterInputs({ onBlur, dateRange, setDateTimePicked }) {
1813
- const [isFocus, setIsFocus] = useState(false);
1814
- const [inputValues, setInputValues] = useState({});
1815
- const formatDisplayDate = useCallback((timestamp, isEnd = false) => {
1816
- if (!dateRange.isVersion || (isEnd && dateRange.isCurrentVersion))
1817
- return formatDate(timestamp, 'FULL');
1818
- return formatDate(timestamp, 'FULL_WITH_TIME');
1819
- }, [dateRange.isVersion, dateRange.isCurrentVersion]);
1820
- useEffect(() => {
1821
- if (isFocus)
1822
- return;
1823
- setInputValues({
1824
- since: formatDisplayDate(dateRange.since),
1825
- until: formatDisplayDate(dateRange.until, true),
1826
- });
1827
- }, [dateRange, formatDisplayDate]);
1828
- function handleStartInputValueChange(value) {
1829
- setInputValues((prevState) => {
1830
- return { ...prevState, since: value };
1831
- });
1832
- if (isValidDate(value)) {
1833
- const newSinceDate = convertDateToTz(value).startOf('day');
1834
- const untilDate = convertDateToTz(dateRange.until).endOf('day');
1835
- const endDate = newSinceDate.isAfter(untilDate) ? newSinceDate.endOf('day') : untilDate;
1836
- setDateTimePicked({
1837
- start: dayjsTzToLocalTZ(newSinceDate).toDate(),
1838
- end: dayjsTzToLocalTZ(endDate).toDate(),
1839
- });
1840
- }
1841
- }
1842
- function handleEndInputValueChange(value) {
1843
- setInputValues((prevState) => ({ ...prevState, until: value }));
1844
- if (isValidDate(value)) {
1845
- const nowEndOfDay = dayjsTz().endOf('day');
1846
- const newUntilDate = convertDateToTz(value).endOf('day');
1847
- const clampedUntil = newUntilDate.isAfter(nowEndOfDay) ? nowEndOfDay : newUntilDate;
1848
- const sinceDate = convertDateToTz(dateRange.since).startOf('day');
1849
- const startDate = clampedUntil.isBefore(sinceDate) ? clampedUntil.startOf('day') : sinceDate;
1850
- setDateTimePicked({
1851
- start: dayjsTzToLocalTZ(startDate).toDate(),
1852
- end: dayjsTzToLocalTZ(clampedUntil).toDate(),
1853
- });
1854
- }
1855
- }
1856
- function handleInputBlur() {
1857
- setIsFocus(false);
1858
- setInputValues({
1859
- since: formatDisplayDate(dateRange.since),
1860
- until: formatDisplayDate(dateRange.until, true),
1861
- });
1862
- onBlur && onBlur();
1863
- }
1864
- function handleFocusStartInput() {
1865
- setIsFocus(true);
1866
- setInputValues({
1867
- ...inputValues,
1868
- since: formatDate(dateRange.since, 'YMD'),
1869
- });
1870
- }
1871
- function handleFocusEndInput() {
1872
- setIsFocus(true);
1873
- setInputValues({
1874
- ...inputValues,
1875
- until: formatDate(dateRange.until, 'YMD'),
1876
- });
1877
- }
1878
- return (jsxs(InlineGrid, { gap: "200", columns: "1fr auto 1fr", children: [jsx(TextField, { role: "combobox", label: 'Since', labelHidden: true,
1879
- // prefix={<Icon source={CalendarIcon} />}
1880
- value: dateRange.since ? inputValues.since : 'MMMM D, YYYY', onChange: handleStartInputValueChange, onBlur: () => handleInputBlur(), onFocus: () => handleFocusStartInput(), autoComplete: "off" }), jsx(InlineStack, { children: jsx(Icon, { source: SvgArrowRightIcon, tone: "subdued" }) }), jsx(TextField, { role: "combobox", label: 'Until', labelHidden: true,
1881
- // prefix={<Icon source={CalendarIcon} />}
1882
- value: dateRange.until ? inputValues.until : 'MMMM D, YYYY', onChange: handleEndInputValueChange, onBlur: () => handleInputBlur(), onFocus: () => handleFocusEndInput(), autoComplete: "off" })] }));
1887
+ const getLast7Days = createLastDaysRange(6);
1888
+ const getLast30Days = createLastDaysRange(29);
1889
+ const getLast90Days = createLastDaysRange(89);
1890
+ const getLast365Days = createLastDaysRange(364);
1891
+ function getLastMonth(date) {
1892
+ return {
1893
+ since: date.subtract(1, 'month').startOf('month').valueOf(),
1894
+ until: date.subtract(1, 'month').endOf('month').valueOf(),
1895
+ };
1883
1896
  }
1884
-
1885
- /**
1886
- * Returns a stateful value, and a set of memoized functions to toggle it,
1887
- * set it to true and set it to false
1888
- */
1889
- function useToggle(initialState) {
1890
- const [value, setState] = useState(initialState);
1897
+ function getLast12Months(date) {
1891
1898
  return {
1892
- value,
1893
- toggle: useCallback(() => setState((state) => !state), []),
1894
- setTrue: useCallback(() => setState(true), []),
1895
- setFalse: useCallback(() => setState(false), []),
1899
+ since: date.subtract(12, 'month').startOf('month').valueOf(),
1900
+ until: date.subtract(1, 'month').endOf('month').valueOf(),
1896
1901
  };
1897
1902
  }
1898
-
1899
- function DateTimeFilterAddition(props) {
1900
- const { setDateTimePicked, dateTimePicked, rangeAddition, allRanges } = props;
1901
- const { value: isExpanded, toggle: toggleExpanded } = useToggle(true);
1902
- const rangesAdditions = rangeAddition?.rangers || [];
1903
- const handleChangeFilterByOption = (value) => {
1904
- const alias = value[0];
1905
- const result = allRanges.find((range) => range.alias === alias) || allRanges[0];
1906
- setDateTimePicked({
1907
- start: dayjsTz(result?.since).toDate(),
1908
- end: dayjsTz(result?.until).toDate(),
1909
- alias: result?.alias,
1910
- });
1903
+ function getLastYear(date) {
1904
+ return {
1905
+ since: date.subtract(1, 'year').startOf('year').valueOf(),
1906
+ until: date.subtract(1, 'year').endOf('year').valueOf(),
1911
1907
  };
1912
- const options = rangesAdditions.map((range) => {
1913
- const selected = dateTimePicked.alias === range.alias;
1908
+ }
1909
+ const getMonthAndYearByDateFilter = (month, year, date) => {
1910
+ const endDate = dayjs(date);
1911
+ const endMonthFilter = endDate.month();
1912
+ const endYearFilter = endDate.year();
1913
+ if (endYearFilter !== year || endMonthFilter !== month) {
1914
+ const prev = endDate.subtract(1, 'month');
1914
1915
  return {
1915
- value: range.alias,
1916
- label: (jsxs(Text, { as: "span", truncate: true, children: [jsx(Text, { as: "span", variant: 'bodyMd', fontWeight: selected ? 'semibold' : 'regular', children: range.title }), range.description && (jsxs(Fragment, { children: [' ', jsx(Text, { as: "span", variant: 'bodyXs', fontWeight: 'regular', tone: "subdued", children: `(${range.description})` })] }))] })),
1916
+ month: prev.month(),
1917
+ year: prev.year(),
1917
1918
  };
1918
- });
1919
- if (!rangeAddition || rangesAdditions.length === 0)
1920
- return;
1921
- return (jsxs(Box, { borderBlockEndWidth: '025', borderColor: 'border', paddingBlock: '200', children: [jsx("div", { className: "px-1.5", children: jsx(GDiv, { onClick: toggleExpanded, "aria-expanded": isExpanded, className: cls('hover:bg-surface-hover cursor-pointer rounded-lg p-1.5'), children: jsxs(InlineStack, { align: "space-between", blockAlign: "center", children: [jsx(Text, { as: "span", variant: "bodyMd", children: rangeAddition.title }), jsx(Box, { children: jsx(Icon, { source: isExpanded ? SvgChevronUpIcon : SvgChevronDownIcon }) })] }) }) }), jsx(Collapsible, { open: isExpanded, id: "date-time-filter-periods-collapsible", transition: { duration: '200ms', timingFunction: 'ease-in-out' }, children: jsx(GOptionList, { options: options, selected: dateTimePicked ? [dateTimePicked.alias] : [], onChange: handleChangeFilterByOption }) })] }));
1922
- }
1919
+ }
1920
+ return { month, year };
1921
+ };
1923
1922
 
1924
- function DateTimeFilters(props) {
1925
- const { setDateTimePicked, dateTimePicked, allRanges, isCompare } = props;
1926
- const { DATE_TIME_FILTERS } = useDateTimeFilter();
1927
- const { mdDown } = useBreakpoints();
1928
- const rangesDefault = isCompare ? [...DATE_TIME_COMPARISON_FILTERS] : [...DATE_TIME_FILTERS];
1929
- const handleChangeFilterBySelect = (value) => {
1930
- const result = allRanges.find(({ title, alias }) => title === value || alias === value) || allRanges[0];
1931
- setDateTimePicked({
1932
- start: dayjsTz(result?.since).toDate(),
1933
- end: dayjsTz(result?.until).toDate(),
1934
- alias: result?.alias,
1935
- });
1923
+ var CompareDateTimePickerAlias;
1924
+ (function (CompareDateTimePickerAlias) {
1925
+ CompareDateTimePickerAlias["NO_COMPARISON"] = "noComparison";
1926
+ CompareDateTimePickerAlias["PREVIOUS_PERIOD"] = "previousPeriod";
1927
+ CompareDateTimePickerAlias["PREVIOUS_WEEK"] = "previousWeek";
1928
+ CompareDateTimePickerAlias["PREVIOUS_MONTH"] = "previousMonth";
1929
+ CompareDateTimePickerAlias["PREVIOUS_QUARTER"] = "previousQuarter";
1930
+ CompareDateTimePickerAlias["PREVIOUS_YEAR"] = "previousYear";
1931
+ })(CompareDateTimePickerAlias || (CompareDateTimePickerAlias = {}));
1932
+ const PREVIOUS_PERIOD_FILTER = {
1933
+ title: 'Previous period',
1934
+ alias: CompareDateTimePickerAlias.PREVIOUS_PERIOD,
1935
+ since: 0,
1936
+ until: 0,
1937
+ };
1938
+ const DATE_TIME_COMPARISON_FILTERS = [
1939
+ {
1940
+ title: 'No comparison',
1941
+ alias: CompareDateTimePickerAlias.NO_COMPARISON,
1942
+ since: 0,
1943
+ until: 0,
1944
+ },
1945
+ PREVIOUS_PERIOD_FILTER,
1946
+ {
1947
+ title: 'Previous week',
1948
+ alias: CompareDateTimePickerAlias.PREVIOUS_WEEK,
1949
+ since: 0,
1950
+ until: 0,
1951
+ },
1952
+ {
1953
+ title: 'Previous quarter',
1954
+ alias: CompareDateTimePickerAlias.PREVIOUS_QUARTER,
1955
+ since: 0,
1956
+ until: 0,
1957
+ },
1958
+ {
1959
+ title: 'Previous month',
1960
+ alias: CompareDateTimePickerAlias.PREVIOUS_MONTH,
1961
+ since: 0,
1962
+ until: 0,
1963
+ },
1964
+ {
1965
+ title: 'Previous year',
1966
+ alias: CompareDateTimePickerAlias.PREVIOUS_YEAR,
1967
+ since: 0,
1968
+ until: 0,
1969
+ },
1970
+ ];
1971
+ const COMPARE_DATE_TIME_FILTERS_MAP = {
1972
+ [CompareDateTimePickerAlias.NO_COMPARISON]: getNoComparison,
1973
+ [CompareDateTimePickerAlias.PREVIOUS_PERIOD]: getPreviousPeriod,
1974
+ [CompareDateTimePickerAlias.PREVIOUS_WEEK]: getPreviousWeek,
1975
+ [CompareDateTimePickerAlias.PREVIOUS_QUARTER]: getPreviousQuarter,
1976
+ [CompareDateTimePickerAlias.PREVIOUS_MONTH]: getPreviousMonth,
1977
+ [CompareDateTimePickerAlias.PREVIOUS_YEAR]: getPreviousYear,
1978
+ };
1979
+
1980
+ const useDateTimeFilter = () => {
1981
+ const currentDate = dayjsTzToLocalTZ().startOf('day');
1982
+ const mappings = getDateTimeFilterMapping();
1983
+ const TODAY_CONFIG = mappings[MainDateTimePickerAlias.TODAY];
1984
+ const TODAY_DATE_RANGE = {
1985
+ ...TODAY_CONFIG,
1986
+ ...TODAY_CONFIG.getDateRange(currentDate),
1936
1987
  };
1937
- const handleChangeFilterByOption = (value) => {
1938
- const result = allRanges.find((range) => range.alias === value[0]) || allRanges[0];
1939
- setDateTimePicked({
1940
- start: dayjsTz(result?.since).toDate(),
1941
- end: dayjsTz(result?.until).toDate(),
1942
- alias: result?.alias,
1943
- });
1988
+ const YESTERDAY_CONFIG = mappings[MainDateTimePickerAlias.YESTERDAY];
1989
+ const YESTERDAY_DATE_RANGE = {
1990
+ ...YESTERDAY_CONFIG,
1991
+ ...YESTERDAY_CONFIG.getDateRange(currentDate),
1944
1992
  };
1945
- return (jsx(Box, { maxWidth: mdDown ? '516px' : '250px', width: mdDown ? '100%' : '250px', padding: { xs: '500', md: '0' }, paddingBlockEnd: { xs: '100', md: '0' }, children: mdDown ? (jsx(Select, { label: "dateRangeLabel", labelHidden: true, onChange: (value) => handleChangeFilterBySelect(value), value: dateTimePicked?.title || dateTimePicked?.alias || '', options: allRanges.map(({ alias, title }) => title || alias) })) : (jsx(Scrollable, { style: { maxHeight: '356px' }, children: jsx(Box, { children: jsxs(BlockStack, { children: [jsx(DateTimeFilterAddition, { ...props }), jsx(OptionList, { options: rangesDefault.map((range) => ({
1946
- value: range.alias,
1947
- label: range.title,
1948
- })), selected: dateTimePicked ? [dateTimePicked.alias] : [], onChange: (value) => handleChangeFilterByOption(value) })] }) }) })) }));
1949
- }
1950
-
1951
- const useCompareDateTimePicker = ({ ranges, onApply }) => {
1952
- const allRanges = ranges || DATE_TIME_COMPARISON_FILTERS;
1953
- const { compareDateTimePicked, setCompareDateTimePicked } = useDateTimePickerContext();
1954
- const { dateTimePicked: mainDateRange } = useDateTimePickerContext();
1955
- const [dateRange, setDateRange] = useState(compareDateTimePicked);
1956
- const [{ month, year }, setDate] = useState({
1957
- month: dayjsTz(compareDateTimePicked.since).month(),
1958
- year: dayjsTz(compareDateTimePicked.since).year(),
1959
- });
1960
- const onMonthChange = (month, year) => {
1961
- setDate({ month, year });
1993
+ const LAST_7_DAYS_CONFIG = mappings[MainDateTimePickerAlias.LAST_7_DAYS];
1994
+ const LAST_7_DAYS_DATE_RANGE = {
1995
+ ...LAST_7_DAYS_CONFIG,
1996
+ ...LAST_7_DAYS_CONFIG.getDateRange(currentDate),
1962
1997
  };
1963
- const onCalendarChange = ({ start, end, alias }) => {
1964
- const newDateRange = allRanges.find((range) => {
1965
- return range.alias === alias;
1966
- });
1967
- // If the alias is not found, set the custom date range
1968
- if (!newDateRange) {
1969
- setDateRange({
1970
- alias: 'custom',
1971
- title: 'Custom',
1972
- since: start.getTime(),
1973
- until: end.getTime(),
1974
- });
1975
- return;
1976
- }
1977
- setDateRange({
1978
- ...newDateRange,
1979
- ...COMPARE_DATE_TIME_FILTERS_MAP[alias]({
1980
- since: mainDateRange.since,
1981
- until: mainDateRange.until,
1982
- }),
1983
- });
1998
+ const LAST_30_DAYS_CONFIG = mappings[MainDateTimePickerAlias.LAST_30_DAYS];
1999
+ const LAST_30_DAYS_DATE_RANGE = {
2000
+ ...LAST_30_DAYS_CONFIG,
2001
+ ...LAST_30_DAYS_CONFIG.getDateRange(currentDate),
1984
2002
  };
1985
- const apply = () => {
1986
- setCompareDateTimePicked(dateRange);
1987
- onApply?.(dateRange);
2003
+ const LAST_90_DAYS_CONFIG = mappings[MainDateTimePickerAlias.LAST_90_DAYS];
2004
+ const LAST_90_DAYS_DATE_RANGE = {
2005
+ ...LAST_90_DAYS_CONFIG,
2006
+ ...LAST_90_DAYS_CONFIG.getDateRange(currentDate),
1988
2007
  };
1989
- const cancel = () => {
1990
- setDateRange(compareDateTimePicked);
2008
+ const LAST_365_DAYS_CONFIG = mappings[MainDateTimePickerAlias.LAST_365_DAYS];
2009
+ const LAST_365_DAYS_DATE_RANGE = {
2010
+ ...LAST_365_DAYS_CONFIG,
2011
+ ...LAST_365_DAYS_CONFIG.getDateRange(currentDate),
1991
2012
  };
1992
- const onChange = ({ end }) => {
1993
- setDate(getMonthAndYearByDateFilter(month, year, end));
2013
+ const LAST_MONTH_CONFIG = mappings[MainDateTimePickerAlias.LAST_MONTH];
2014
+ const LAST_MONTH_DATE_RANGE = {
2015
+ ...LAST_MONTH_CONFIG,
2016
+ ...LAST_MONTH_CONFIG.getDateRange(currentDate),
1994
2017
  };
1995
- return {
1996
- month,
1997
- year,
1998
- setDate,
1999
- dateRange,
2000
- apply,
2001
- cancel,
2002
- compareDateTimePicked,
2003
- onChange,
2004
- onMonthChange,
2005
- onCalendarChange,
2018
+ const LAST_12_MONTHS_CONFIG = mappings[MainDateTimePickerAlias.LAST_12_MONTHS];
2019
+ const LAST_12_MONTHS_DATE_RANGE = {
2020
+ ...LAST_12_MONTHS_CONFIG,
2021
+ ...LAST_12_MONTHS_CONFIG.getDateRange(currentDate),
2006
2022
  };
2007
- };
2008
-
2009
- const BaseTimePicker = (props) => {
2010
- const { dateTimeFilters, rangeAddition, popoverProps, activatorProps, actionProps, isCompare, buttonValue, activator, } = props;
2011
- const initialPicked = rangeAddition?.initialPicked;
2012
- const ranges = [...(dateTimeFilters || []), ...(rangeAddition?.rangers || [])];
2013
- const useHookDateTimePicker = isCompare ? useCompareDateTimePicker : useDateTimePicker;
2014
- const { month, year, dateRange, apply, cancel, onMonthChange, onCalendarChange, onChange } = useHookDateTimePicker({
2015
- ranges,
2016
- initialPicked,
2017
- onApply: props.onApply,
2018
- });
2019
- const { t } = useTranslation();
2020
- const { mdDown, lgUp } = useBreakpoints();
2021
- const shouldShowMultiMonth = lgUp;
2022
- const rawTooltipContent = useMemo(() => {
2023
- // Only show tooltip when selecting Period (isVersion)
2024
- if (!dateRange.isVersion || !dateRange.since || !dateRange.until)
2025
- return;
2026
- return formatDateTimeRange({
2027
- since: dateRange.since,
2028
- until: dateRange.until,
2029
- isShowNow: dateRange.isCurrentVersion,
2030
- });
2031
- }, [dateRange.since, dateRange.until, dateRange.isVersion, dateRange.isCurrentVersion]);
2032
- const [popoverActive, setPopoverActive] = useState(false);
2033
- // Freeze tooltip content while popover is open to prevent button remount (focus/CSS loss)
2034
- const datePickerRef = useRef(null);
2035
- const tooltipContentRef = useRef(rawTooltipContent);
2036
- if (!popoverActive)
2037
- tooltipContentRef.current = rawTooltipContent;
2038
- const tooltipContent = tooltipContentRef.current;
2039
- //@ts-ignore
2040
- function nodeContainsDescendant(rootNode, descendant) {
2041
- if (rootNode === descendant) {
2042
- return true;
2043
- }
2044
- let parent = descendant.parentNode;
2045
- while (parent != null) {
2046
- if (parent === rootNode) {
2047
- return true;
2048
- }
2049
- parent = parent.parentNode;
2050
- }
2051
- return false;
2052
- }
2053
- //@ts-ignore
2054
- function isNodeWithinPopover(node) {
2055
- return datePickerRef?.current ? nodeContainsDescendant(datePickerRef.current, node) : false;
2056
- }
2057
- //@ts-ignore
2058
- function handleInputBlur({ relatedTarget }) {
2059
- const isRelatedTargetWithinPopover = relatedTarget != null && isNodeWithinPopover(relatedTarget);
2060
- // If focus moves from the TextField to the Popover
2061
- // we don't want to close the popover
2062
- if (isRelatedTargetWithinPopover) {
2063
- return;
2064
- }
2065
- setPopoverActive(false);
2066
- }
2067
- function applyFunc() {
2068
- apply();
2069
- setPopoverActive(false);
2070
- }
2071
- function cancelFunc() {
2072
- cancel();
2073
- setPopoverActive(false);
2074
- }
2075
- const handleTogglePopover = () => {
2076
- if (isCompare) {
2077
- return;
2078
- }
2079
- setPopoverActive(!popoverActive);
2023
+ const LAST_YEAR_CONFIG = mappings[MainDateTimePickerAlias.LAST_YEAR];
2024
+ const LAST_YEAR_DATE_RANGE = {
2025
+ ...LAST_YEAR_CONFIG,
2026
+ ...LAST_YEAR_CONFIG.getDateRange(currentDate),
2080
2027
  };
2081
- const onChangeDateTimeFilter = (data) => {
2082
- onCalendarChange(data);
2083
- onChange(data);
2028
+ const DATE_TIME_FILTERS = [
2029
+ TODAY_DATE_RANGE,
2030
+ YESTERDAY_DATE_RANGE,
2031
+ LAST_7_DAYS_DATE_RANGE,
2032
+ LAST_30_DAYS_DATE_RANGE,
2033
+ LAST_90_DAYS_DATE_RANGE,
2034
+ LAST_365_DAYS_DATE_RANGE,
2035
+ LAST_MONTH_DATE_RANGE,
2036
+ LAST_12_MONTHS_DATE_RANGE,
2037
+ LAST_YEAR_DATE_RANGE,
2038
+ ];
2039
+ return {
2040
+ DATE_TIME_FILTERS,
2041
+ LAST_7_DAYS_DATE_RANGE,
2042
+ LAST_30_DAYS_DATE_RANGE,
2084
2043
  };
2085
- return (jsx(Popover, { active: popoverActive, autofocusTarget: "none", preferredAlignment: "right", preferredPosition: "below", fluidContent: true, sectioned: false, fullHeight: true, activator: jsx(GBlockCenter, { height: "100%", minHeight: "28px", align: "center", children: jsx(GTooltip, { content: tooltipContent, maxWidth: activator ? 'large' : 'extra-large', children: jsx(Box, { children: activator ? (activator({ onClick: handleTogglePopover, value: buttonValue })) : (jsx(Button, { size: "slim", icon: !isCompare ? SvgCalendarIcon : undefined, onClick: handleTogglePopover, ...activatorProps, children: buttonValue })) }) }) }), onClose: cancelFunc, ...popoverProps, children: jsxs(Scrollable, { vertical: true, scrollbarWidth: "thin", className: "max-w-[100%]", children: [jsx(Popover.Pane, { fixed: true, children: jsx("div", { ref: datePickerRef, children: jsxs(InlineGrid, { columns: {
2086
- xs: '1fr',
2087
- md: 'max-content max-content',
2088
- }, gap: "0", children: [jsx(DateTimeFilters, { setDateTimePicked: onChangeDateTimeFilter, dateTimePicked: dateRange, rangeAddition: rangeAddition, allRanges: ranges, isCompare: isCompare }), jsx(Box, { padding: "400", maxWidth: mdDown ? '320px' : '516px', borderInlineStartWidth: "025", borderColor: "border-secondary", children: jsxs(BlockStack, { gap: "400", children: [jsx(DateTimeFilterInputs, { setDateTimePicked: onCalendarChange, dateRange: dateRange, onBlur: () => handleInputBlur }), jsx("div", { children: jsx(DatePicker, { month: month, year: year, selected: !dateRange.since && !dateRange.until
2089
- ? undefined
2090
- : {
2091
- start: dayjs(dateRange.since).toDate(),
2092
- end: dayjs(dateRange.until).toDate(),
2093
- }, onMonthChange: onMonthChange, onChange: onCalendarChange, multiMonth: shouldShowMultiMonth, allowRange: true, disableDatesAfter: dayjsTzToDate() }) }), actionProps && (jsx(GButton, { ...actionProps, onClick: () => {
2094
- setPopoverActive(false);
2095
- actionProps.onClick?.();
2096
- } }))] }) })] }) }) }), jsx(Popover.Pane, { fixed: true, children: jsx(Box, { padding: "400", borderBlockStartWidth: "025", borderColor: "border-secondary", children: jsx(InlineStack, { align: "end", gap: "200", children: jsxs(ButtonGroup, { children: [jsx(Button, { onClick: cancelFunc, children: t('Cancel') }), jsx(Button, { variant: "primary", onClick: applyFunc, children: t('Apply') })] }) }) }) })] }) }));
2097
- };
2098
-
2099
- const CompareTimePicker = (props) => {
2100
- const { rangeAddition, popoverProps } = props;
2101
- const initialPicked = rangeAddition?.initialPicked;
2102
- const dateTimeFilters = DATE_TIME_COMPARISON_FILTERS;
2103
- const ranges = [...dateTimeFilters, ...(rangeAddition?.rangers || [])];
2104
- const { t } = useTranslation();
2105
- const { compareDateTimePicked } = useCompareDateTimePicker({ ranges, initialPicked });
2106
- const buttonValue = useMemo(() => {
2107
- if (compareDateTimePicked.alias === CompareDateTimePickerAlias.NO_COMPARISON) {
2108
- return t('No comparison');
2109
- }
2110
- return t('Compare to: {{value}}', {
2111
- value: getDateRangeTitle(compareDateTimePicked.since, compareDateTimePicked.until),
2112
- });
2113
- }, [compareDateTimePicked, t]);
2114
- return (jsx(BaseTimePicker, { dateTimeFilters: dateTimeFilters, rangeAddition: rangeAddition, popoverProps: popoverProps, isCompare: true, buttonValue: buttonValue }));
2115
2044
  };
2116
2045
 
2117
- const MainTimePicker = (props) => {
2118
- const { rangeAddition, popoverProps, activator, onApply, activatorProps, actionProps } = props;
2046
+ const DateTimePickerContext = createContext({
2047
+ dateTimePicked: {
2048
+ since: dayjsTz().valueOf(),
2049
+ until: dayjsTz().valueOf(),
2050
+ title: 'Today',
2051
+ alias: 'today',
2052
+ },
2053
+ compareDateTimePicked: PREVIOUS_PERIOD_FILTER,
2054
+ setDateTimePicked: () => { },
2055
+ setCompareDateTimePicked: () => { },
2056
+ resetDateVersion: () => { },
2057
+ });
2058
+ const DateTimePickerProvider = ({ children, initDate, initDateCompare, }) => {
2059
+ const [dateTimePicked, setDateTimePicked] = useState(initDate || {
2060
+ since: dayjsTz().set('hour', 0).valueOf(),
2061
+ until: dayjsTz().set('hour', 0).valueOf(),
2062
+ title: 'Today',
2063
+ alias: 'today',
2064
+ });
2119
2065
  const { DATE_TIME_FILTERS } = useDateTimeFilter();
2120
- const dateTimeFilters = DATE_TIME_FILTERS;
2121
- const additionalRanges = rangeAddition?.rangers || [];
2122
- const initialPicked = rangeAddition?.initialPicked;
2123
- const ranges = [...dateTimeFilters, ...additionalRanges];
2124
- const { dateTimePicked } = useDateTimePicker({ ranges, initialPicked });
2125
- const getButtonValue = () => {
2126
- if (dateTimePicked.isVersion && additionalRanges.length > 0) {
2127
- const time = dateTimePicked.description ? `at ${dateTimePicked.description}` : '';
2128
- return `Period: ${dateTimePicked.title} ${time}`;
2129
- }
2130
- if (dateTimePicked.alias === 'custom') {
2131
- return getDateRangeTitle(dateTimePicked.since, dateTimePicked.until);
2132
- }
2133
- return dateTimePicked.title;
2134
- };
2135
- return (jsx(BaseTimePicker, { activatorProps: activatorProps, dateTimeFilters: dateTimeFilters, rangeAddition: rangeAddition, popoverProps: popoverProps, actionProps: actionProps, buttonValue: getButtonValue(), activator: activator, onApply: onApply }));
2136
- };
2137
-
2138
- const GTimePicker = (props) => {
2139
- const { isCompare, ...timePickerProps } = props;
2140
- return (jsxs(InlineStack, { gap: "200", children: [jsx(MainTimePicker, { ...timePickerProps }), isCompare && (jsx(CompareTimePicker, { rangeAddition: timePickerProps.rangeAddition, popoverProps: timePickerProps.popoverProps }))] }));
2141
- };
2142
-
2143
- const GViewBySelector = ({ activatorText, selected, options, minWidth, maxWidth, preferredAlignment = 'right', onSelect, }) => {
2144
- const [popoverActive, setPopoverActive] = useState(false);
2145
- const [itemHover, setItemHover] = useState(null);
2146
- const togglePopoverActive = () => setPopoverActive((prev) => !prev);
2147
- const selectedOption = useMemo(() => {
2148
- return options.find((item) => item.id === selected);
2149
- }, [options, selected]);
2150
- const activatorContent = useMemo(() => {
2151
- if (selectedOption) {
2152
- const content = selectedOption.title ?? selectedOption.content;
2153
- return activatorText ? `${activatorText}: ${content}` : content;
2154
- }
2155
- return activatorText;
2156
- }, [selectedOption, activatorText]);
2157
- const handleSelect = (value) => {
2158
- onSelect(value);
2159
- setPopoverActive(false);
2066
+ const getCompareDateTimePicked = useCallback((alias, source = dateTimePicked) => {
2067
+ return {
2068
+ ...PREVIOUS_PERIOD_FILTER,
2069
+ ...COMPARE_DATE_TIME_FILTERS_MAP[alias]({
2070
+ since: source.since,
2071
+ until: source.until,
2072
+ alias: source.alias,
2073
+ }),
2074
+ };
2075
+ }, [dateTimePicked]);
2076
+ const [compareDateTimePicked, setCompareDateTimePicked] = useState(initDateCompare || getCompareDateTimePicked(CompareDateTimePickerAlias.PREVIOUS_PERIOD));
2077
+ const updateCompareDateTimePicked = useCallback((source) => {
2078
+ if (compareDateTimePicked.alias === 'custom' ||
2079
+ compareDateTimePicked.alias === CompareDateTimePickerAlias.NO_COMPARISON)
2080
+ return;
2081
+ setCompareDateTimePicked(getCompareDateTimePicked(compareDateTimePicked.alias, source));
2082
+ }, [compareDateTimePicked, getCompareDateTimePicked]);
2083
+ const resetDateVersion = () => {
2084
+ const since = dayjs(dateTimePicked.since).startOf('day').valueOf();
2085
+ const until = dayjs(dateTimePicked.until).startOf('day').valueOf();
2086
+ const dateFilter = DATE_TIME_FILTERS.find((filter) => filter.since === since && filter.until === until);
2087
+ setDateTimePicked({
2088
+ ...dateTimePicked,
2089
+ isVersion: false,
2090
+ versionId: undefined,
2091
+ isCurrentVersion: false,
2092
+ description: '',
2093
+ title: dateFilter?.title || dateTimePicked.title,
2094
+ alias: dateFilter?.alias || 'custom',
2095
+ });
2160
2096
  };
2161
- return (jsx(Popover, { active: popoverActive, activator: jsx(GActivatorPopover, { active: popoverActive, content: activatorContent, textProps: { variant: 'bodySm' }, onClick: togglePopoverActive }), autofocusTarget: "first-node", fluidContent: true, onClose: togglePopoverActive, preferredAlignment: preferredAlignment, children: jsx(Box, { maxWidth: maxWidth, minWidth: minWidth, padding: "200", children: jsx(BlockStack, { gap: "200", children: options.map((option) => {
2162
- const isSelected = option.id === selected;
2163
- const isHover = itemHover === option.id;
2164
- const borderColor = isSelected ? 'input-border' : isHover ? 'border-hover' : 'transparent';
2165
- return (jsx(Box, { padding: "150", borderWidth: "025", borderColor: borderColor, borderRadius: "100", children: jsx("div", { onClick: () => handleSelect(option.id), className: "cursor-pointer", onMouseEnter: () => setItemHover(option.id), onMouseLeave: () => setItemHover(null), children: jsxs(InlineStack, { gap: "300", align: "space-between", blockAlign: "center", wrap: false, children: [jsxs(InlineStack, { gap: "300", blockAlign: "center", wrap: false, children: [jsx("div", { className: "bg-surface-secondary flex items-center justify-center rounded-md min-w-[184px] h-[92px]", children: jsx("img", { src: option.icon, alt: option.content, className: "w-full h-full object-contain" }) }), jsxs(BlockStack, { gap: "100", children: [jsx(Text, { as: "span", variant: "bodyMd", fontWeight: "semibold", children: option.content }), jsx(Text, { as: "p", variant: "bodyMd", tone: "subdued", children: option.helpText })] })] }), isSelected && (jsx(Box, { children: jsx(Icon, { source: SvgCheckIcon }) }))] }) }) }, option.id));
2166
- }) }) }) }));
2097
+ const onSetDateTimePicked = useCallback((value) => {
2098
+ setDateTimePicked(value);
2099
+ updateCompareDateTimePicked(value);
2100
+ }, [updateCompareDateTimePicked]);
2101
+ return (jsx(DateTimePickerContext.Provider, { value: {
2102
+ dateTimePicked,
2103
+ setDateTimePicked: onSetDateTimePicked,
2104
+ compareDateTimePicked,
2105
+ setCompareDateTimePicked,
2106
+ resetDateVersion,
2107
+ }, children: children }));
2167
2108
  };
2168
-
2169
- const ChoiceHelpText = ({ item }) => {
2170
- return (jsxs(Text, { as: "p", variant: "bodyMd", children: [item.description, item.inlineAction && (jsx(Link, { monochrome: true, onClick: () => {
2171
- if (item.inlineAction?.onAction) {
2172
- item.inlineAction?.onAction();
2173
- }
2174
- else {
2175
- window.open(item.inlineAction?.url, item.inlineAction?.target ?? '_blank');
2176
- }
2177
- }, children: item.inlineAction?.content }))] }));
2109
+ const useDateTimePickerContext = () => {
2110
+ const context = useContext(DateTimePickerContext);
2111
+ if (!context) {
2112
+ throw new Error('useDateTimePickerContext must be used within a DateTimePickerProvider');
2113
+ }
2114
+ return context;
2178
2115
  };
2179
2116
 
2180
- const GChoice = ({ item, disabled, isActive, suffix, isMultipleSelect, onClick, children, position = 'right', boxProps, activeStyle, }) => {
2181
- const paddingBox = {
2182
- paddingBlockStart: '200',
2183
- paddingBlockEnd: '200',
2184
- paddingInlineStart: '400',
2185
- paddingInlineEnd: '400',
2186
- };
2187
- const emitOnClick = (e) => {
2188
- e.preventDefault();
2189
- e.stopPropagation();
2190
- if (disabled)
2191
- return;
2192
- onClick?.(item.value, item.type);
2193
- };
2194
- const styleByState = useMemo(() => {
2195
- if (!isActive) {
2196
- return {
2197
- box: { outlineWidth: '025', outlineColor: 'border' },
2198
- text: { fontWeight: 'regular' },
2117
+ const useDateTimePicker = ({ ranges, initialPicked, onApply }) => {
2118
+ const { DATE_TIME_FILTERS } = useDateTimeFilter();
2119
+ const allRanges = ranges || DATE_TIME_FILTERS;
2120
+ const { dateTimePicked, setDateTimePicked } = useDateTimePickerContext();
2121
+ const [dateRange, setDateRange] = useState(dateTimePicked);
2122
+ const [{ month, year }, setDate] = useState({
2123
+ month: dayjs(dateTimePicked.since).month(),
2124
+ year: dayjs(dateTimePicked.since).year(),
2125
+ });
2126
+ useEffect(() => {
2127
+ if (dateTimePicked) {
2128
+ const untilDate = new Date(dateTimePicked.until);
2129
+ const monthDiff = (referenceDate, newDate) => {
2130
+ return newDate.month - referenceDate.month + 12 * (referenceDate.year - newDate.year);
2199
2131
  };
2132
+ monthDiff({ year, month }, {
2133
+ year: untilDate.getFullYear(),
2134
+ month: untilDate.getMonth(),
2135
+ });
2136
+ // if (monthDifference > 1 || monthDifference < 0) {
2137
+ // setDate({
2138
+ // month: untilDate.getMonth(),
2139
+ // year: untilDate.getFullYear(),
2140
+ // });
2141
+ // }
2200
2142
  }
2201
- if (activeStyle)
2202
- return activeStyle;
2203
- return {
2204
- box: { outlineWidth: '050', outlineColor: 'border-inverse' },
2205
- text: { fontWeight: 'semibold' },
2206
- };
2207
- }, [activeStyle, isActive]);
2208
- const checkBoxComponent = () => {
2209
- return (jsx(Checkbox, { label: jsx(InlineStack, { gap: "100", children: jsx(Text, { truncate: true, as: "p", variant: "bodyMd", fontWeight: styleByState.text.fontWeight, children: item.label }) }), disabled: disabled, checked: isActive, name: item.type, ...(item.description && { helpText: jsx(ChoiceHelpText, { item: item }) }) }));
2143
+ }, [dateTimePicked, month, year]);
2144
+ const onMonthChange = (month, year) => {
2145
+ setDate({ month, year });
2210
2146
  };
2211
- const radioComponent = () => {
2212
- return (jsx(RadioButton, { label: jsxs(InlineStack, { gap: "100", children: [jsx(Text, { truncate: true, as: "p", variant: "bodyMd", fontWeight: styleByState.text.fontWeight, children: item.label }), item.icon] }), disabled: disabled, checked: isActive, name: item.type, ...(item.description && { helpText: jsx(ChoiceHelpText, { item: item }) }) }));
2147
+ const onCalendarChange = (value) => {
2148
+ const { start, end, alias } = value;
2149
+ const customDateRange = {
2150
+ alias: 'custom',
2151
+ title: 'Custom',
2152
+ since: start.getTime(),
2153
+ until: end.getTime(),
2154
+ };
2155
+ const newDateRange = allRanges.find((range) => {
2156
+ const isSameAlias = range.alias === alias;
2157
+ const isSameUntil = range.until === end.getTime();
2158
+ const isSameSince = range.since === start.getTime();
2159
+ // const isSameVersionId = !!range.versionId && !!versionId && range.versionId === versionId;
2160
+ const isSameTime = isSameSince && isSameUntil;
2161
+ return isSameAlias || isSameTime;
2162
+ });
2163
+ const finalDateRange = newDateRange || initialPicked || customDateRange;
2164
+ setDateRange(finalDateRange);
2213
2165
  };
2214
- const renderInputComponent = () => {
2215
- return isMultipleSelect ? checkBoxComponent() : radioComponent();
2166
+ const onChange = ({ end }) => {
2167
+ setDate(getMonthAndYearByDateFilter(month, year, end));
2216
2168
  };
2217
- return (jsx("div", { onClick: (e) => emitOnClick(e), className: 'GChoice-ChoiceBox', children: jsx(Box, { borderRadius: "300", padding: '050', children: jsx(Box, { ...paddingBox, ...styleByState.box, shadow: "100", borderRadius: "300", ...boxProps, children: jsx(BlockStack, { gap: "0", children: jsxs(InlineStack, { align: "space-between", children: [position === 'left' && children, renderInputComponent(), position === 'right' && children, suffix] }) }) }) }, item.value) }));
2218
- };
2219
-
2220
- const GChartSkeleton = () => {
2221
- return jsx(GSkeletonDisplayText, { height: "188px" });
2222
- };
2223
-
2224
- const LINE_SERIES_COLORS = {
2225
- comparison: SERIES_COLORS.comparison,
2226
- single: SERIES_COLORS.current,
2227
- all: [...SERIES_COLORS.all],
2228
- };
2229
- const MetricChartProvider = ({ children, minHeight = CHART_MIN_HEIGHT, seriesColors = LINE_SERIES_COLORS, }) => {
2230
- return (jsx(PolarisVizProvider, { themes: {
2231
- Light: {
2232
- chartContainer: {
2233
- minHeight,
2234
- },
2235
- grid: {
2236
- horizontalOverflow: true,
2237
- verticalOverflow: true,
2238
- horizontalMargin: 0,
2239
- },
2240
- seriesColors,
2241
- },
2242
- }, children: children }));
2243
- };
2244
-
2245
- const useFormatLineChartData = ({ metricKey, columnTypes }) => {
2246
- const { formatData } = useAnalyticData();
2247
- const formatter = metricKey ? columnTypes?.[metricKey] : undefined;
2248
- const formatValue = (value) => {
2249
- return String(formatData({ value, formatter }));
2169
+ const apply = () => {
2170
+ setDateTimePicked(dateRange);
2171
+ onApply?.(dateRange);
2250
2172
  };
2251
- const yAxisOptions = {
2252
- labelFormatter: (value) => {
2253
- return formatValue(Number(value) || 0);
2254
- },
2173
+ const cancel = () => {
2174
+ setDateRange(dateTimePicked);
2255
2175
  };
2256
- return { formatValue, yAxisOptions };
2257
- };
2258
-
2259
- const useWindowSize = () => {
2260
- const [windowSize, setWindowSize] = useState(() => ({
2261
- width: typeof window !== 'undefined' ? window.innerWidth : 0,
2262
- height: typeof window !== 'undefined' ? window.innerHeight : 0,
2263
- }));
2264
- const windowWidth = useMemo(() => {
2265
- return {
2266
- xs: windowSize.width <= 768,
2267
- md: 768 < windowSize.width && windowSize.width <= 1024,
2268
- lg: windowSize.width > 1024,
2269
- xsDown: windowSize.width < 768,
2270
- '1200Down': windowSize.width < 1200,
2271
- '1040Down': windowSize.width < 1040,
2272
- };
2273
- }, [windowSize.width]);
2274
- const isMobileTabletView = !windowWidth.lg;
2275
- const isMobileView = windowWidth.xs;
2276
2176
  useEffect(() => {
2277
- const windowSizeHandler = () => {
2278
- setWindowSize({ width: window.innerWidth, height: window.innerHeight });
2279
- };
2280
- window.addEventListener('resize', windowSizeHandler);
2281
- return () => {
2282
- window.removeEventListener('resize', windowSizeHandler);
2283
- };
2284
- }, []);
2285
- return { windowSize, windowWidth, isMobileTabletView, isMobileView };
2286
- };
2287
-
2288
- const MetricChart = ({ lineChartData, isLoading, isEmptyMetricData, columnTypes, metricKey, }) => {
2289
- const { formatValue, yAxisOptions } = useFormatLineChartData({ metricKey, columnTypes: columnTypes || {} });
2290
- if (!metricKey) {
2291
- return jsx(Fragment, {});
2292
- }
2293
- if (isLoading) {
2294
- return jsx(GChartSkeleton, {});
2295
- }
2296
- if (isEmptyMetricData) {
2297
- return jsx(MetricChartEmpty, { title: "No data yet", description: "Data needs time to gather" });
2298
- }
2299
- return (jsx(MetricChartProvider, { children: jsx(LineChart, { data: lineChartData, yAxisOptions: yAxisOptions, theme: "Light", tooltipOptions: {
2300
- titleFormatter: () => `${ANALYTICS_METRIC_TOOLTIP[metricKey]?.title ?? ''}`,
2301
- keyFormatter: (value) => {
2302
- return value;
2303
- },
2304
- renderTooltipContent(data) {
2305
- return jsx(MetricChartTooltip, { data: data, formatValue: formatValue });
2306
- },
2307
- }, showLegend: true }) }));
2308
- };
2309
-
2310
- var IMAGE_ANALYTIC_EMPTY = "data:image/png;base64,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";
2311
-
2312
- const MetricChartEmpty = ({ boxProps, minHeight, description, title }) => {
2313
- return (jsx(Box, { minWidth: "100%", ...boxProps, children: jsx(GBlockCenter, { minHeight: minHeight, children: jsx(Box, { padding: '400', children: jsxs(BlockStack, { gap: "400", align: "center", inlineAlign: "center", children: [jsx("div", { className: "h-[80px] w-[80px]", children: jsx(GThumbnail, { source: IMAGE_ANALYTIC_EMPTY, width: "80px", height: "80px", alt: title, classRemoved: true }) }), jsxs(BlockStack, { gap: "200", align: "center", inlineAlign: "center", children: [jsx(Text, { as: "h4", variant: "headingSm", fontWeight: "semibold", children: title }), jsx(Text, { as: "h4", variant: "bodyMd", tone: "subdued", children: description })] })] }) }) }) }));
2314
- };
2315
-
2316
- const DownIcon8px = () => {
2317
- return (jsxs("svg", { width: "8", height: "8", viewBox: "0 0 8 8", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [jsx("g", { clipPath: "url(#clip0_18114_1160)", children: jsx("path", { d: "M1 1L6.5 6.5M6.5 6.5V1.5M6.5 6.5H1.5", stroke: "#8A8A8A", strokeWidth: "1.5" }) }), jsx("defs", { children: jsx("clipPath", { id: "clip0_18114_1160", children: jsx("rect", { width: "8", height: "8", fill: "white" }) }) })] }));
2318
- };
2319
-
2320
- const UpIcon8px = () => {
2321
- return (jsxs("svg", { width: "8", height: "8", viewBox: "0 0 8 8", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [jsx("g", { clipPath: "url(#clip0_18114_1146)", children: jsx("path", { d: "M1 7L6.5 1.5M6.5 1.5H1.5M6.5 1.5V6.5", stroke: "#29845A", strokeWidth: "1.5" }) }), jsx("defs", { children: jsx("clipPath", { id: "clip0_18114_1146", children: jsx("rect", { width: "8", height: "8", fill: "white", transform: "matrix(0 -1 1 0 0 8)" }) }) })] }));
2322
- };
2323
-
2324
- const MetricPercentage = ({ change }) => {
2325
- if (typeof change !== 'number') {
2326
- return jsx("div", { style: { height: '2px', width: '11px', backgroundColor: '#8A8A8A' } });
2327
- }
2328
- return (jsxs("div", { style: {
2329
- display: 'flex',
2330
- maxHeight: '20px',
2331
- width: 'fit-content',
2332
- alignItems: 'center',
2333
- gap: '4px',
2334
- borderRadius: '8px',
2335
- fontSize: '12px',
2336
- color: change > 0 ? TREND_TONE.POSITIVE : TREND_TONE.NEUTRAL,
2337
- }, children: [change < 0 && (jsx(InlineStack, { align: "center", children: jsx(DownIcon8px, {}) })), change > 0 && (jsx(InlineStack, { align: "center", children: jsx(UpIcon8px, {}) })), jsx(Text, { as: "span", variant: "bodyXs", fontWeight: "semibold", children: formatPercentage(Math.abs(change || 0)) })] }));
2338
- };
2339
-
2340
- const MetricChartTooltip = ({ data, formatValue }) => {
2341
- const { activeIndex } = data;
2342
- const currentData = data?.dataSeries[0]?.data[activeIndex];
2343
- const previousData = data?.dataSeries[1]?.data[activeIndex];
2344
- const formatPercent = () => {
2345
- const value = currentData.trend?.value;
2346
- if (!value)
2347
- return PLACEHOLDER_VALUE;
2348
- const valueNumber = Number(value.replace(/[%~]/g, ''));
2349
- if (currentData.trend?.trend === 'negative') {
2350
- return valueNumber * -1;
2177
+ if (dateTimePicked) {
2178
+ setDateRange(dateTimePicked);
2179
+ setDate({
2180
+ month: dayjs(dateTimePicked.since).month(),
2181
+ year: dayjs(dateTimePicked.since).year(),
2182
+ });
2351
2183
  }
2352
- return valueNumber;
2184
+ }, [dateTimePicked]);
2185
+ return {
2186
+ month,
2187
+ year,
2188
+ setDate,
2189
+ dateRange,
2190
+ apply,
2191
+ cancel,
2192
+ dateTimePicked,
2193
+ onChange,
2194
+ onMonthChange,
2195
+ onCalendarChange,
2353
2196
  };
2354
- return (jsx("div", { className: "w-fit min-w-[175px]", children: jsx(Card, { padding: '200', children: jsxs(BlockStack, { gap: '100', children: [jsx(Text, { as: "p", variant: "bodySm", fontWeight: "semibold", children: data.formatters?.titleFormatter?.(data.title || '') || data.title }), jsxs(BlockStack, { gap: '100', children: [jsxs(InlineStack, { gap: '400', align: "space-between", blockAlign: "center", children: [jsxs(InlineStack, { gap: '100', blockAlign: "center", children: [jsx("div", { className: "h-[2px] w-[12px] rounded-[10px] bg-[#4FA9EA]" }), jsx(Text, { as: "p", variant: "bodySm", fontWeight: "medium", tone: "subdued", children: currentData.tooltipKey })] }), jsxs(InlineStack, { blockAlign: "center", gap: "100", children: [jsx(Text, { as: "span", variant: "bodySm", fontWeight: "semibold", children: formatValue(currentData.value) }), jsx(MetricPercentage, { change: formatPercent() })] })] }), jsxs(InlineStack, { gap: '400', align: "space-between", blockAlign: "center", children: [jsxs(InlineStack, { gap: '100', blockAlign: "center", children: [jsx("div", { className: "w-[12px] border border-dashed border-[#A1CAE7]" }), jsx(Text, { as: "p", variant: "bodySm", tone: "subdued", fontWeight: "medium", children: previousData.tooltipKey })] }), jsxs(InlineStack, { blockAlign: "center", gap: "100", children: [jsx(Text, { as: "span", variant: "bodySm", fontWeight: "semibold", children: formatValue(previousData.value) }), jsx("div", { className: "opacity-0", children: jsx(MetricPercentage, { change: formatPercent() }) })] })] })] })] }) }) }));
2355
- };
2356
-
2357
- const MetricInfoSkeleton = ({ isShowOneLine }) => {
2358
- if (isShowOneLine) {
2359
- return (jsx(Box, { width: "40%", children: jsx(SkeletonBodyText, { lines: 1 }) }));
2360
- }
2361
- return (jsxs(BlockStack, { gap: "200", children: [jsx(Box, { width: "60%", children: jsx(SkeletonBodyText, { lines: 1 }) }), jsx(Box, { width: "40%", children: jsx(SkeletonBodyText, { lines: 1 }) })] }));
2362
- };
2363
-
2364
- const MetricDonutChartSkeleton = () => {
2365
- return (jsx(Card, { children: jsxs(BlockStack, { gap: "400", children: [jsx(MetricInfoSkeleton, { isShowOneLine: true }), jsx(GChartSkeleton, {})] }) }));
2366
- };
2367
-
2368
- const MetricValueSummary = ({ totalValue, hideComparison }) => (jsx(BlockStack, { gap: "200", children: jsxs(InlineStack, { blockAlign: "center", gap: "200", wrap: false, children: [jsx(InlineStack, { blockAlign: "center", gap: "200", children: jsx(Text, { as: "span", variant: "headingSm", children: totalValue.value }) }), !hideComparison && jsx(MetricPercentage, { change: totalValue.change })] }) }));
2369
-
2370
- const MetricInfoBlock = ({ item, isHovered, isLoading, hideComparison, titleVariant = 'headingMd', titleFontWeight, onClickTitle, }) => {
2371
- const { key, title, totalValue } = item;
2372
- const tooltip = ANALYTICS_METRIC_TOOLTIP[key];
2373
- if (isLoading)
2374
- return jsx(MetricInfoSkeleton, {});
2375
- return (jsxs(BlockStack, { gap: "200", children: [jsx("div", { className: "hover:cursor-pointer hover:text-[--p-color-text-link-hover]", onClick: (e) => {
2376
- e?.stopPropagation();
2377
- onClickTitle?.(key);
2378
- }, children: jsxs(InlineStack, { wrap: false, children: [jsx(Box, { maxWidth: "100%", overflowX: "hidden", children: jsx(GTooltipCard, { tooltip: tooltip, children: jsx(Text, { as: "span", variant: titleVariant, fontWeight: titleFontWeight, truncate: true, children: title }) }) }), isHovered && (jsx("div", { className: "flex h-[20px] w-[20px] items-center", children: jsx(Icon, { source: SvgChevronRightIcon, tone: "inherit" }) }))] }) }), jsx(MetricValueSummary, { totalValue: totalValue, hideComparison: hideComparison })] }));
2379
- };
2380
-
2381
- const MetricChartTab = ({ item, isActive, isLoading, hideComparison, onSelect, onClickTitle, }) => {
2382
- const [isHovered, setIsHovered] = useState(false);
2383
- const isHighlighted = isActive || isHovered;
2384
- return (jsx("div", { className: "w-full cursor-pointer overflow-hidden", onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), onClick: () => onSelect(item.key), children: jsx(Box, { paddingBlock: "150", paddingInline: "300", borderRadius: "200", background: isHighlighted ? 'bg-surface-active' : undefined, children: jsx(MetricInfoBlock, { item: item, isHovered: isHovered, isLoading: isLoading, hideComparison: hideComparison, titleVariant: "headingSm", titleFontWeight: "semibold", onClickTitle: onClickTitle }) }) }));
2385
2197
  };
2386
2198
 
2387
- const GSelectableMetricChartCard = ({ metricInfo, dataChart, defaultActiveTab, isLoading, isEmptyMetricData, hideComparison, currentPeriodLabel = DEFAULT_CURRENT_PERIOD_LABEL, previousPeriodLabel = DEFAULT_PREVIOUS_PERIOD_LABEL, columnTypes, }) => {
2388
- const [activeTab, setActiveTab] = useState(defaultActiveTab);
2389
- const lineChartData = useMemo(() => {
2390
- const chartData = activeTab ? dataChart[activeTab] : undefined;
2391
- if (!chartData)
2199
+ const useVersionDateTimeFilters = (versions) => {
2200
+ const { t } = useTranslation();
2201
+ const rangers = useMemo(() => {
2202
+ if (!versions?.length)
2392
2203
  return [];
2393
- const currentSeries = { name: currentPeriodLabel, data: chartData.current };
2394
- if (hideComparison)
2395
- return [currentSeries];
2396
- return [currentSeries, { name: previousPeriodLabel, data: chartData.previous, isComparison: true }];
2397
- }, [activeTab, dataChart, hideComparison, currentPeriodLabel, previousPeriodLabel]);
2398
- return (jsxs(Card, { children: [jsx("div", { style: {
2399
- display: 'grid',
2400
- gridTemplateColumns: `repeat(${metricInfo.length}, 1fr)`,
2401
- gap: '16px',
2402
- marginBottom: '16px',
2403
- }, children: metricInfo.map((item) => (jsx(MetricChartTab, { item: item, isActive: activeTab === item.key, isLoading: isLoading, hideComparison: hideComparison, onSelect: setActiveTab }, item.key))) }), jsx(MetricChart, { lineChartData: lineChartData, isLoading: isLoading, isEmptyMetricData: isEmptyMetricData, metricKey: activeTab, columnTypes: columnTypes })] }));
2204
+ return convertToDateTimeFilters(versions);
2205
+ }, [versions]);
2206
+ const rangeAddition = {
2207
+ title: t('Experiment periods'),
2208
+ rangers,
2209
+ };
2210
+ return { rangeAddition };
2404
2211
  };
2405
2212
 
2406
- const calculatePercentageChange = (current, previous) => {
2407
- if (current === 0 && previous === 0) {
2408
- return undefined;
2213
+ function DateTimeFilterInputs({ onBlur, dateRange, setDateTimePicked }) {
2214
+ const [isFocus, setIsFocus] = useState(false);
2215
+ const [inputValues, setInputValues] = useState({});
2216
+ const formatDisplayDate = useCallback((timestamp, isEnd = false) => {
2217
+ if (!dateRange.isVersion || (isEnd && dateRange.isCurrentVersion))
2218
+ return formatDate(timestamp, 'FULL');
2219
+ return formatDate(timestamp, 'FULL_WITH_TIME');
2220
+ }, [dateRange.isVersion, dateRange.isCurrentVersion]);
2221
+ useEffect(() => {
2222
+ if (isFocus)
2223
+ return;
2224
+ setInputValues({
2225
+ since: formatDisplayDate(dateRange.since),
2226
+ until: formatDisplayDate(dateRange.until, true),
2227
+ });
2228
+ }, [dateRange, formatDisplayDate]);
2229
+ function handleStartInputValueChange(value) {
2230
+ setInputValues((prevState) => {
2231
+ return { ...prevState, since: value };
2232
+ });
2233
+ if (isValidDate(value)) {
2234
+ const newSinceDate = convertDateToTz(value).startOf('day');
2235
+ const untilDate = convertDateToTz(dateRange.until).endOf('day');
2236
+ const endDate = newSinceDate.isAfter(untilDate) ? newSinceDate.endOf('day') : untilDate;
2237
+ setDateTimePicked({
2238
+ start: dayjsTzToLocalTZ(newSinceDate).toDate(),
2239
+ end: dayjsTzToLocalTZ(endDate).toDate(),
2240
+ });
2241
+ }
2409
2242
  }
2410
- if (previous === 0) {
2411
- return current > 0 ? '100%' : '0%';
2243
+ function handleEndInputValueChange(value) {
2244
+ setInputValues((prevState) => ({ ...prevState, until: value }));
2245
+ if (isValidDate(value)) {
2246
+ const nowEndOfDay = dayjsTz().endOf('day');
2247
+ const newUntilDate = convertDateToTz(value).endOf('day');
2248
+ const clampedUntil = newUntilDate.isAfter(nowEndOfDay) ? nowEndOfDay : newUntilDate;
2249
+ const sinceDate = convertDateToTz(dateRange.since).startOf('day');
2250
+ const startDate = clampedUntil.isBefore(sinceDate) ? clampedUntil.startOf('day') : sinceDate;
2251
+ setDateTimePicked({
2252
+ start: dayjsTzToLocalTZ(startDate).toDate(),
2253
+ end: dayjsTzToLocalTZ(clampedUntil).toDate(),
2254
+ });
2255
+ }
2412
2256
  }
2413
- const change = ((current - previous) / previous) * 100;
2414
- return `${Math.abs(change).toFixed(0)}%`;
2415
- };
2416
- const computeDonutData = ({ name, currentValue, prevValue, hasPreviousData, }) => ({
2417
- name,
2418
- data: [{ key: 'value', value: currentValue }],
2419
- metadata: {
2420
- trend: {
2421
- value: hasPreviousData ? calculatePercentageChange(currentValue, prevValue) : undefined,
2422
- direction: currentValue >= prevValue ? 'upward' : 'downward',
2423
- trend: currentValue >= prevValue ? 'positive' : 'negative',
2424
- },
2425
- },
2426
- });
2427
- const getTotalCountByType = (stats, type) => {
2428
- const item = stats?.find((stat) => stat?.type?.toLowerCase() === type.toLowerCase());
2429
- return item?.total ?? 0;
2430
- };
2431
- const buildBreakdownDonutData = ({ targets, metricKey, totalsRow, comparisonTotalsRow, sort, }) => {
2432
- const items = parseBreakdownItems(totalsRow?.[metricKey]);
2433
- const comparisonItems = parseBreakdownItems(comparisonTotalsRow?.[metricKey]);
2434
- const hasPreviousData = !!comparisonTotalsRow?.[metricKey];
2435
- const result = targets.map(({ value, label }) => computeDonutData({
2436
- name: label,
2437
- currentValue: getTotalCountByType(items, value),
2438
- prevValue: getTotalCountByType(comparisonItems, value),
2439
- hasPreviousData,
2440
- }));
2441
- const getValue = (item) => item.data[0]?.value ?? 0;
2442
- return sort ? [...result].sort((a, b) => getValue(b) - getValue(a)) : result;
2257
+ function handleInputBlur() {
2258
+ setIsFocus(false);
2259
+ setInputValues({
2260
+ since: formatDisplayDate(dateRange.since),
2261
+ until: formatDisplayDate(dateRange.until, true),
2262
+ });
2263
+ onBlur && onBlur();
2264
+ }
2265
+ function handleFocusStartInput() {
2266
+ setIsFocus(true);
2267
+ setInputValues({
2268
+ ...inputValues,
2269
+ since: formatDate(dateRange.since, 'YMD'),
2270
+ });
2271
+ }
2272
+ function handleFocusEndInput() {
2273
+ setIsFocus(true);
2274
+ setInputValues({
2275
+ ...inputValues,
2276
+ until: formatDate(dateRange.until, 'YMD'),
2277
+ });
2278
+ }
2279
+ return (jsxs(InlineGrid, { gap: "200", columns: "1fr auto 1fr", children: [jsx(TextField, { role: "combobox", label: 'Since', labelHidden: true,
2280
+ // prefix={<Icon source={CalendarIcon} />}
2281
+ value: dateRange.since ? inputValues.since : 'MMMM D, YYYY', onChange: handleStartInputValueChange, onBlur: () => handleInputBlur(), onFocus: () => handleFocusStartInput(), autoComplete: "off" }), jsx(InlineStack, { children: jsx(Icon, { source: SvgArrowRightIcon, tone: "subdued" }) }), jsx(TextField, { role: "combobox", label: 'Until', labelHidden: true,
2282
+ // prefix={<Icon source={CalendarIcon} />}
2283
+ value: dateRange.until ? inputValues.until : 'MMMM D, YYYY', onChange: handleEndInputValueChange, onBlur: () => handleInputBlur(), onFocus: () => handleFocusEndInput(), autoComplete: "off" })] }));
2284
+ }
2285
+
2286
+ function DateTimeFilterAddition(props) {
2287
+ const { setDateTimePicked, dateTimePicked, rangeAddition, allRanges } = props;
2288
+ const { value: isExpanded, toggle: toggleExpanded } = useToggle(true);
2289
+ const rangesAdditions = rangeAddition?.rangers || [];
2290
+ const handleChangeFilterByOption = (value) => {
2291
+ const alias = value[0];
2292
+ const result = allRanges.find((range) => range.alias === alias) || allRanges[0];
2293
+ setDateTimePicked({
2294
+ start: dayjsTz(result?.since).toDate(),
2295
+ end: dayjsTz(result?.until).toDate(),
2296
+ alias: result?.alias,
2297
+ });
2298
+ };
2299
+ const options = rangesAdditions.map((range) => {
2300
+ const selected = dateTimePicked.alias === range.alias;
2301
+ return {
2302
+ value: range.alias,
2303
+ label: (jsxs(Text, { as: "span", truncate: true, children: [jsx(Text, { as: "span", variant: 'bodyMd', fontWeight: selected ? 'semibold' : 'regular', children: range.title }), range.description && (jsxs(Fragment, { children: [' ', jsx(Text, { as: "span", variant: 'bodyXs', fontWeight: 'regular', tone: "subdued", children: `(${range.description})` })] }))] })),
2304
+ };
2305
+ });
2306
+ if (!rangeAddition || rangesAdditions.length === 0)
2307
+ return;
2308
+ return (jsxs(Box, { borderBlockEndWidth: '025', borderColor: 'border', paddingBlock: '200', children: [jsx("div", { className: "px-1.5", children: jsx(GDiv, { onClick: toggleExpanded, "aria-expanded": isExpanded, className: cls('hover:bg-surface-hover cursor-pointer rounded-lg p-1.5'), children: jsxs(InlineStack, { align: "space-between", blockAlign: "center", children: [jsx(Text, { as: "span", variant: "bodyMd", children: rangeAddition.title }), jsx(Box, { children: jsx(Icon, { source: isExpanded ? SvgChevronUpIcon : SvgChevronDownIcon }) })] }) }) }), jsx(Collapsible, { open: isExpanded, id: "date-time-filter-periods-collapsible", transition: { duration: '200ms', timingFunction: 'ease-in-out' }, children: jsx(GOptionList, { options: options, selected: dateTimePicked ? [dateTimePicked.alias] : [], onChange: handleChangeFilterByOption }) })] }));
2309
+ }
2310
+
2311
+ function DateTimeFilters(props) {
2312
+ const { setDateTimePicked, dateTimePicked, allRanges, isCompare } = props;
2313
+ const { DATE_TIME_FILTERS } = useDateTimeFilter();
2314
+ const { mdDown } = useBreakpoints();
2315
+ const rangesDefault = isCompare ? [...DATE_TIME_COMPARISON_FILTERS] : [...DATE_TIME_FILTERS];
2316
+ const handleChangeFilterBySelect = (value) => {
2317
+ const result = allRanges.find(({ title, alias }) => title === value || alias === value) || allRanges[0];
2318
+ setDateTimePicked({
2319
+ start: dayjsTz(result?.since).toDate(),
2320
+ end: dayjsTz(result?.until).toDate(),
2321
+ alias: result?.alias,
2322
+ });
2323
+ };
2324
+ const handleChangeFilterByOption = (value) => {
2325
+ const result = allRanges.find((range) => range.alias === value[0]) || allRanges[0];
2326
+ setDateTimePicked({
2327
+ start: dayjsTz(result?.since).toDate(),
2328
+ end: dayjsTz(result?.until).toDate(),
2329
+ alias: result?.alias,
2330
+ });
2331
+ };
2332
+ return (jsx(Box, { maxWidth: mdDown ? '516px' : '250px', width: mdDown ? '100%' : '250px', padding: { xs: '500', md: '0' }, paddingBlockEnd: { xs: '100', md: '0' }, children: mdDown ? (jsx(Select, { label: "dateRangeLabel", labelHidden: true, onChange: (value) => handleChangeFilterBySelect(value), value: dateTimePicked?.title || dateTimePicked?.alias || '', options: allRanges.map(({ alias, title }) => title || alias) })) : (jsx(Scrollable, { style: { maxHeight: '356px' }, children: jsx(Box, { children: jsxs(BlockStack, { children: [jsx(DateTimeFilterAddition, { ...props }), jsx(OptionList, { options: rangesDefault.map((range) => ({
2333
+ value: range.alias,
2334
+ label: range.title,
2335
+ })), selected: dateTimePicked ? [dateTimePicked.alias] : [], onChange: (value) => handleChangeFilterByOption(value) })] }) }) })) }));
2336
+ }
2337
+
2338
+ const useCompareDateTimePicker = ({ ranges, onApply }) => {
2339
+ const allRanges = ranges || DATE_TIME_COMPARISON_FILTERS;
2340
+ const { compareDateTimePicked, setCompareDateTimePicked } = useDateTimePickerContext();
2341
+ const { dateTimePicked: mainDateRange } = useDateTimePickerContext();
2342
+ const [dateRange, setDateRange] = useState(compareDateTimePicked);
2343
+ const [{ month, year }, setDate] = useState({
2344
+ month: dayjsTz(compareDateTimePicked.since).month(),
2345
+ year: dayjsTz(compareDateTimePicked.since).year(),
2346
+ });
2347
+ const onMonthChange = (month, year) => {
2348
+ setDate({ month, year });
2349
+ };
2350
+ const onCalendarChange = ({ start, end, alias }) => {
2351
+ const newDateRange = allRanges.find((range) => {
2352
+ return range.alias === alias;
2353
+ });
2354
+ // If the alias is not found, set the custom date range
2355
+ if (!newDateRange) {
2356
+ setDateRange({
2357
+ alias: 'custom',
2358
+ title: 'Custom',
2359
+ since: start.getTime(),
2360
+ until: end.getTime(),
2361
+ });
2362
+ return;
2363
+ }
2364
+ setDateRange({
2365
+ ...newDateRange,
2366
+ ...COMPARE_DATE_TIME_FILTERS_MAP[alias]({
2367
+ since: mainDateRange.since,
2368
+ until: mainDateRange.until,
2369
+ }),
2370
+ });
2371
+ };
2372
+ const apply = () => {
2373
+ setCompareDateTimePicked(dateRange);
2374
+ onApply?.(dateRange);
2375
+ };
2376
+ const cancel = () => {
2377
+ setDateRange(compareDateTimePicked);
2378
+ };
2379
+ const onChange = ({ end }) => {
2380
+ setDate(getMonthAndYearByDateFilter(month, year, end));
2381
+ };
2382
+ return {
2383
+ month,
2384
+ year,
2385
+ setDate,
2386
+ dateRange,
2387
+ apply,
2388
+ cancel,
2389
+ compareDateTimePicked,
2390
+ onChange,
2391
+ onMonthChange,
2392
+ onCalendarChange,
2393
+ };
2443
2394
  };
2444
2395
 
2445
- const DONUT_CHART_MIN_HEIGHT = 294;
2446
- const COMPACT_MAX_WIDTH = 1500;
2447
- const MetricDonutChartCard = ({ label, metricKey, targets, totalsRow, comparisonTotalsRow, sort, isLoading, isEmptyMetricData, minHeight = DONUT_CHART_MIN_HEIGHT, onClick, }) => {
2448
- const tooltip = ANALYTICS_METRIC_TOOLTIP[metricKey];
2449
- const { windowWidth, windowSize } = useWindowSize();
2450
- const [isHovered, setIsHovered] = useState(false);
2451
- const data = useMemo(() => buildBreakdownDonutData({ targets, metricKey, totalsRow, comparisonTotalsRow, sort }), [targets, metricKey, totalsRow, comparisonTotalsRow, sort]);
2452
- if (isLoading) {
2453
- return jsx(MetricDonutChartSkeleton, {});
2396
+ const BaseTimePicker = (props) => {
2397
+ const { dateTimeFilters, rangeAddition, popoverProps, activatorProps, actionProps, isCompare, buttonValue, activator, } = props;
2398
+ const initialPicked = rangeAddition?.initialPicked;
2399
+ const ranges = [...(dateTimeFilters || []), ...(rangeAddition?.rangers || [])];
2400
+ const useHookDateTimePicker = isCompare ? useCompareDateTimePicker : useDateTimePicker;
2401
+ const { month, year, dateRange, apply, cancel, onMonthChange, onCalendarChange, onChange } = useHookDateTimePicker({
2402
+ ranges,
2403
+ initialPicked,
2404
+ onApply: props.onApply,
2405
+ });
2406
+ const { t } = useTranslation();
2407
+ const { mdDown, lgUp } = useBreakpoints();
2408
+ const shouldShowMultiMonth = lgUp;
2409
+ const rawTooltipContent = useMemo(() => {
2410
+ // Only show tooltip when selecting Period (isVersion)
2411
+ if (!dateRange.isVersion || !dateRange.since || !dateRange.until)
2412
+ return;
2413
+ return formatDateTimeRange({
2414
+ since: dateRange.since,
2415
+ until: dateRange.until,
2416
+ isShowNow: dateRange.isCurrentVersion,
2417
+ });
2418
+ }, [dateRange.since, dateRange.until, dateRange.isVersion, dateRange.isCurrentVersion]);
2419
+ const [popoverActive, setPopoverActive] = useState(false);
2420
+ // Freeze tooltip content while popover is open to prevent button remount (focus/CSS loss)
2421
+ const datePickerRef = useRef(null);
2422
+ const tooltipContentRef = useRef(rawTooltipContent);
2423
+ if (!popoverActive)
2424
+ tooltipContentRef.current = rawTooltipContent;
2425
+ const tooltipContent = tooltipContentRef.current;
2426
+ //@ts-ignore
2427
+ function nodeContainsDescendant(rootNode, descendant) {
2428
+ if (rootNode === descendant) {
2429
+ return true;
2430
+ }
2431
+ let parent = descendant.parentNode;
2432
+ while (parent != null) {
2433
+ if (parent === rootNode) {
2434
+ return true;
2435
+ }
2436
+ parent = parent.parentNode;
2437
+ }
2438
+ return false;
2454
2439
  }
2455
- const formatValue = (value) => {
2456
- return numberWithCommas(`${value}`);
2440
+ //@ts-ignore
2441
+ function isNodeWithinPopover(node) {
2442
+ return datePickerRef?.current ? nodeContainsDescendant(datePickerRef.current, node) : false;
2443
+ }
2444
+ //@ts-ignore
2445
+ function handleInputBlur({ relatedTarget }) {
2446
+ const isRelatedTargetWithinPopover = relatedTarget != null && isNodeWithinPopover(relatedTarget);
2447
+ // If focus moves from the TextField to the Popover
2448
+ // we don't want to close the popover
2449
+ if (isRelatedTargetWithinPopover) {
2450
+ return;
2451
+ }
2452
+ setPopoverActive(false);
2453
+ }
2454
+ function applyFunc() {
2455
+ apply();
2456
+ setPopoverActive(false);
2457
+ }
2458
+ function cancelFunc() {
2459
+ cancel();
2460
+ setPopoverActive(false);
2461
+ }
2462
+ const handleTogglePopover = () => {
2463
+ if (isCompare) {
2464
+ return;
2465
+ }
2466
+ setPopoverActive(!popoverActive);
2457
2467
  };
2458
- const handleClickTitle = (event) => {
2459
- event.stopPropagation();
2460
- onClick();
2468
+ const onChangeDateTimeFilter = (data) => {
2469
+ onCalendarChange(data);
2470
+ onChange(data);
2461
2471
  };
2462
- const isCompactView = windowWidth.lg && windowSize.width < COMPACT_MAX_WIDTH;
2463
- return (jsx("div", { onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), children: jsx(Card, { children: jsxs(BlockStack, { gap: "200", children: [jsx(InlineStack, { children: jsx("div", { className: "hover:cursor-pointer hover:text-[--p-color-text-link-hover]", onClick: handleClickTitle, children: jsxs(InlineStack, { children: [jsx(GTooltipCard, { tooltip: tooltip, children: jsx(Text, { as: "h3", variant: "headingMd", children: label }) }), isHovered && jsx(Icon, { source: SvgChevronRightIcon, tone: "inherit" })] }) }) }), jsx("div", { className: cls('flex items-center justify-center', {
2464
- 'max-h-[250px] overflow-hidden': isCompactView,
2465
- }), children: isEmptyMetricData ? (jsx(MetricChartEmpty, { title: "No data yet", description: "Data needs time to gather" })) : (jsx(MetricChartProvider, { minHeight: minHeight, seriesColors: {}, children: jsx(DonutChart, { data: data, legendPosition: "left", showLegendValues: true, showLegend: true, theme: "Light", tooltipOptions: {
2466
- valueFormatter: formatValue,
2467
- }, labelFormatter: formatValue }) })) })] }) }) }));
2472
+ return (jsx(Popover, { active: popoverActive, autofocusTarget: "none", preferredAlignment: "right", preferredPosition: "below", fluidContent: true, sectioned: false, fullHeight: true, activator: jsx(GBlockCenter, { height: "100%", minHeight: "28px", align: "center", children: jsx(GTooltip, { content: tooltipContent, maxWidth: activator ? 'large' : 'extra-large', children: jsx(Box, { children: activator ? (activator({ onClick: handleTogglePopover, value: buttonValue })) : (jsx(Button, { size: "slim", icon: !isCompare ? SvgCalendarIcon : undefined, onClick: handleTogglePopover, ...activatorProps, children: buttonValue })) }) }) }), onClose: cancelFunc, ...popoverProps, children: jsxs(Scrollable, { vertical: true, scrollbarWidth: "thin", className: "max-w-[100%]", children: [jsx(Popover.Pane, { fixed: true, children: jsx("div", { ref: datePickerRef, children: jsxs(InlineGrid, { columns: {
2473
+ xs: '1fr',
2474
+ md: 'max-content max-content',
2475
+ }, gap: "0", children: [jsx(DateTimeFilters, { setDateTimePicked: onChangeDateTimeFilter, dateTimePicked: dateRange, rangeAddition: rangeAddition, allRanges: ranges, isCompare: isCompare }), jsx(Box, { padding: "400", maxWidth: mdDown ? '320px' : '516px', borderInlineStartWidth: "025", borderColor: "border-secondary", children: jsxs(BlockStack, { gap: "400", children: [jsx(DateTimeFilterInputs, { setDateTimePicked: onCalendarChange, dateRange: dateRange, onBlur: () => handleInputBlur }), jsx("div", { children: jsx(DatePicker, { month: month, year: year, selected: !dateRange.since && !dateRange.until
2476
+ ? undefined
2477
+ : {
2478
+ start: dayjs(dateRange.since).toDate(),
2479
+ end: dayjs(dateRange.until).toDate(),
2480
+ }, onMonthChange: onMonthChange, onChange: onCalendarChange, multiMonth: shouldShowMultiMonth, allowRange: true, disableDatesAfter: dayjsTzToDate() }) }), actionProps && (jsx(GButton, { ...actionProps, onClick: () => {
2481
+ setPopoverActive(false);
2482
+ actionProps.onClick?.();
2483
+ } }))] }) })] }) }) }), jsx(Popover.Pane, { fixed: true, children: jsx(Box, { padding: "400", borderBlockStartWidth: "025", borderColor: "border-secondary", children: jsx(InlineStack, { align: "end", gap: "200", children: jsxs(ButtonGroup, { children: [jsx(Button, { onClick: cancelFunc, children: t('Cancel') }), jsx(Button, { variant: "primary", onClick: applyFunc, children: t('Apply') })] }) }) }) })] }) }));
2468
2484
  };
2469
2485
 
2470
- const SingleMetricChartCard = ({ metricInfo, lineChartData, isLoading, hideComparison, columnTypes, isEmptyMetricData, onClickTitle, }) => {
2471
- const [isHovered, setIsHovered] = useState(false);
2472
- return (jsx("div", { onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), children: jsx(Card, { children: jsxs(BlockStack, { gap: "200", children: [jsx(MetricInfoBlock, { item: metricInfo, isHovered: isHovered, isLoading: isLoading, hideComparison: hideComparison, onClickTitle: onClickTitle }), jsx(MetricChart, { lineChartData: lineChartData, isLoading: isLoading, isEmptyMetricData: isEmptyMetricData, columnTypes: columnTypes, metricKey: metricInfo.key })] }) }) }));
2486
+ const CompareTimePicker = (props) => {
2487
+ const { rangeAddition, popoverProps } = props;
2488
+ const initialPicked = rangeAddition?.initialPicked;
2489
+ const dateTimeFilters = DATE_TIME_COMPARISON_FILTERS;
2490
+ const ranges = [...dateTimeFilters, ...(rangeAddition?.rangers || [])];
2491
+ const { t } = useTranslation();
2492
+ const { compareDateTimePicked } = useCompareDateTimePicker({ ranges, initialPicked });
2493
+ const buttonValue = useMemo(() => {
2494
+ if (compareDateTimePicked.alias === CompareDateTimePickerAlias.NO_COMPARISON) {
2495
+ return t('No comparison');
2496
+ }
2497
+ return t('Compare to: {{value}}', {
2498
+ value: getDateRangeTitle(compareDateTimePicked.since, compareDateTimePicked.until),
2499
+ });
2500
+ }, [compareDateTimePicked, t]);
2501
+ return (jsx(BaseTimePicker, { dateTimeFilters: dateTimeFilters, rangeAddition: rangeAddition, popoverProps: popoverProps, isCompare: true, buttonValue: buttonValue }));
2473
2502
  };
2474
2503
 
2475
- var IMAGE_FIRST_SESSION = "data:image/png;base64,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";
2476
-
2477
- var IMAGE_ALL_SESSION = "data:image/png;base64,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";
2478
-
2479
- var EAnalyticMode;
2480
- (function (EAnalyticMode) {
2481
- EAnalyticMode["ALL_SESSION"] = "ALL_SESSION";
2482
- EAnalyticMode["FIRST_SESSION"] = "FIRST_SESSION";
2483
- EAnalyticMode["PAGE_ONLY"] = "PAGE_ONLY";
2484
- })(EAnalyticMode || (EAnalyticMode = {}));
2485
-
2486
- const VIEW_BY_OPTIONS = [
2487
- {
2488
- id: EAnalyticMode.ALL_SESSION,
2489
- content: 'All sessions',
2490
- helpText: 'Count metrics for all sessions where this page shows up anywhere in the journey: before, during, or after other pages.',
2491
- icon: IMAGE_ALL_SESSION,
2492
- },
2493
- {
2494
- id: EAnalyticMode.FIRST_SESSION,
2495
- content: 'Entry session only',
2496
- helpText: 'Count metrics for sessions only where this page was the very first page visited, then track how they moved through the funnel.',
2497
- icon: IMAGE_FIRST_SESSION,
2498
- },
2499
- ];
2500
- const AnalyticModeSelector = ({ activatorText = 'View by', value, onChange }) => {
2501
- const options = useMemo(() => {
2502
- return VIEW_BY_OPTIONS.map((option) => ({
2503
- ...option,
2504
- }));
2505
- }, []);
2506
- const onSelectMode = (value) => {
2507
- onChange(value);
2504
+ const MainTimePicker = (props) => {
2505
+ const { rangeAddition, popoverProps, activator, onApply, activatorProps, actionProps } = props;
2506
+ const { DATE_TIME_FILTERS } = useDateTimeFilter();
2507
+ const dateTimeFilters = DATE_TIME_FILTERS;
2508
+ const additionalRanges = rangeAddition?.rangers || [];
2509
+ const initialPicked = rangeAddition?.initialPicked;
2510
+ const ranges = [...dateTimeFilters, ...additionalRanges];
2511
+ const { dateTimePicked } = useDateTimePicker({ ranges, initialPicked });
2512
+ const getButtonValue = () => {
2513
+ if (dateTimePicked.isVersion && additionalRanges.length > 0) {
2514
+ const time = dateTimePicked.description ? `at ${dateTimePicked.description}` : '';
2515
+ return `Period: ${dateTimePicked.title} ${time}`;
2516
+ }
2517
+ if (dateTimePicked.alias === 'custom') {
2518
+ return getDateRangeTitle(dateTimePicked.since, dateTimePicked.until);
2519
+ }
2520
+ return dateTimePicked.title;
2508
2521
  };
2509
- return (jsx(GViewBySelector, { activatorText: activatorText, options: options, selected: value, onSelect: onSelectMode, maxWidth: "650px" }));
2522
+ return (jsx(BaseTimePicker, { activatorProps: activatorProps, dateTimeFilters: dateTimeFilters, rangeAddition: rangeAddition, popoverProps: popoverProps, actionProps: actionProps, buttonValue: getButtonValue(), activator: activator, onApply: onApply }));
2510
2523
  };
2511
2524
 
2512
- const EXCHANGE_RATE_HELP_URL = 'https://help.shopify.com/en/manual/international/pricing/exchange-rates#auto-convert';
2513
- const CurrencySelector = ({ currencies, selected, preferredAlignment = 'left', activatorText, onSelect, }) => {
2514
- const { t } = useTranslation();
2515
- const onSelectRef = useRef(onSelect);
2516
- const handleSelection = useCallback((value) => {
2517
- onSelectRef.current?.(value);
2518
- }, []);
2519
- const actionItems = useMemo(() => {
2520
- if (!currencies)
2521
- return [];
2522
- const formattedCurrencies = currencies.map((currency) => ({
2523
- content: currency,
2524
- id: currency,
2525
- }));
2526
- const hasCurrencyDefault = formattedCurrencies.some((item) => item.id === DEFAULT_CURRENCY_ANALYTIC);
2527
- if (!hasCurrencyDefault) {
2528
- formattedCurrencies.push({
2529
- content: DEFAULT_CURRENCY_ANALYTIC,
2530
- id: DEFAULT_CURRENCY_ANALYTIC,
2531
- });
2532
- }
2533
- return sortByConditions(formattedCurrencies, [
2534
- { attr: 'content', order: 'asc', preferredValue: DEFAULT_CURRENCY_ANALYTIC },
2535
- ]);
2536
- }, [currencies]);
2537
- const actionListItems = useMemo(() => {
2538
- return actionItems.map((option) => ({
2539
- id: option.id,
2540
- content: option.content,
2541
- onAction: () => handleSelection(option.id),
2542
- active: option.id === selected,
2543
- suffix: option.id === selected && jsx(Icon, { source: SvgCheckIcon, tone: "success" }),
2544
- helpText: option.id === DEFAULT_CURRENCY_ANALYTIC && (jsx(Text, { as: "p", fontWeight: "semibold", children: t('Default') })),
2545
- }));
2546
- }, [actionItems, selected, handleSelection, t]);
2547
- const isHidden = useMemo(() => {
2548
- if (!actionItems?.length)
2549
- return true;
2550
- return actionItems.length === 1 && actionItems[0]?.id === DEFAULT_CURRENCY_ANALYTIC;
2551
- }, [actionItems]);
2552
- useEffect(() => {
2553
- onSelectRef.current = onSelect;
2554
- });
2555
- if (isHidden)
2556
- return null;
2557
- return (jsx(GSelector, { options: actionListItems, selected: selected, variant: "action-list",
2558
- // value originates from our CurrencyCode option ids, so the widen-to-string round trip is safe
2559
- onSelect: (value) => handleSelection(value), activatorText: activatorText ?? t('Currency'), maxWidth: "225px", preferredAlignment: preferredAlignment, helpText: jsx(Box, { padding: "200", paddingBlockStart: "300", paddingBlockEnd: "300", borderColor: "border-tertiary", background: 'bg', children: jsx(GI18NText, { as: "p", variant: "bodyMd", transformers: {
2560
- 1: (text) => (jsx(GTextLink, { linkAction: {
2561
- url: EXCHANGE_RATE_HELP_URL,
2562
- target: '_blank',
2563
- }, children: text }, text + 'text-link')),
2564
- }, children: t("This will follow Shopify's current exchange rate. [1]Read more[]") }) }) }));
2525
+ const GTimePicker = (props) => {
2526
+ const { isCompare, ...timePickerProps } = props;
2527
+ return (jsxs(InlineStack, { gap: "200", children: [jsx(MainTimePicker, { ...timePickerProps }), isCompare && (jsx(CompareTimePicker, { rangeAddition: timePickerProps.rangeAddition, popoverProps: timePickerProps.popoverProps }))] }));
2565
2528
  };
2566
2529
 
2567
- export { ANALYTICS_METRIC_TOOLTIP, AnalyticModeSelector, CAMPAIGN_BACKGROUND_MAIN, CHART_MIN_HEIGHT, COMPARE_DATE_TIME_FILTERS_MAP, ChoiceHelpText, CompareDateTimePickerAlias, CurrencySelector, DATE_TIME_COMPARISON_FILTERS, DEFAULT_CURRENCY_ANALYTIC, DEFAULT_CURRENT_PERIOD_LABEL, DEFAULT_PREVIOUS_PERIOD_LABEL, DateTimeFilterInputs, DateTimeFilters, DateTimePickerContext, DateTimePickerProvider, EAnalyticColumnKey, EAnalyticMode, EDeviceType, EMetricKey, ETrafficSourceType, EVisitorType, GActivatorPopover, GBlockCenter, GButton, GCheckbox, GCheckboxMultiple, GCheckboxSingle, GChoice, GClickable, GDiv, GI18NText, GOptionList, GSelectableMetricChartCard, GSelector, GSkeletonDisplayText, GTextLink, GThumbnail, GTimePicker, GTooltip, GTooltipCard, GViewBySelector, MainDateTimePickerAlias, MetricDonutChartCard, PLACEHOLDER_VALUE, PREVIOUS_PERIOD_FILTER, SERIES_COLORS, SingleMetricChartCard, TARGET_CHANNEL, TARGET_DEVICES, TARGET_VISITOR, THUMB_PRODUCT_DEFAULT, TREND_TONE, convertToDateTimeFilters, createLastDaysRange, formatDate, formatDateTimeRange, formatDayjs, formatMs, formatTime, formatTimeRange, getDateRangeTitle, getDateTimeFilterBase, getDateTimeFilterByAlias, getDateTimeFilterMapping, getEndOfDayBy, getLast12Months, getLast30Days, getLast365Days, getLast7Days, getLast90Days, getLastMonth, getLastYear, getMonthAndYearByDateFilter, getNoComparison, getPreviousMonth, getPreviousPeriod, getPreviousQuarter, getPreviousWeek, getPreviousYear, getToday, getVersionDateDescription, getVersionDateRangeTitle, getYesterday, isDate, isMidnight, isSameDayTimestamp, isValidDate, isValidYearMonthDayDateString, parseYearMonthDayDateString, useDateTimeFilter, useDateTimePicker, useDateTimePickerContext, useVersionDateTimeFilters, variationName };
2530
+ export { AnalyticModeSelector, COMPARE_DATE_TIME_FILTERS_MAP, CompareDateTimePickerAlias, CurrencySelector, DATE_TIME_COMPARISON_FILTERS, DateTimeFilterInputs, DateTimeFilters, DateTimePickerContext, DateTimePickerProvider, GSelectableMetricChartCard, GTimePicker, MainDateTimePickerAlias, MetricDonutChartCard, PREVIOUS_PERIOD_FILTER, SingleMetricChartCard, convertDateToTz, convertToDateTimeFilters, createLastDaysRange, dayjsTz, dayjsTzToDate, dayjsTzToLocalTZ, formatDate, formatDateTimeRange, formatDayjs, formatMs, formatTime, formatTimeRange, getDateRangeTitle, getDateTimeFilterBase, getDateTimeFilterByAlias, getDateTimeFilterMapping, getEndOfDayBy, getInitialTimezone, getLast12Months, getLast30Days, getLast365Days, getLast7Days, getLast90Days, getLastMonth, getLastYear, getMonthAndYearByDateFilter, getNoComparison, getPreviousMonth, getPreviousPeriod, getPreviousQuarter, getPreviousWeek, getPreviousYear, getToday, getVersionDateDescription, getVersionDateRangeTitle, getYesterday, isDate, isMidnight, isSameDayTimestamp, isValidDate, isValidYearMonthDayDateString, parseYearMonthDayDateString, setTz, useDateTimeFilter, useDateTimePicker, useDateTimePickerContext, useVersionDateTimeFilters };