@levi-gemcommerce/analytics 1.0.0-dev.12 → 1.0.0-dev.14

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 (100) 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/constants/breakdown-targets.d.ts +1 -1
  29. package/dist/esm/core/gemxql/builder/clauses/mode-query.d.ts +1 -1
  30. package/dist/esm/core/gemxql/helpers/getTimeDimension.d.ts +1 -1
  31. package/dist/esm/core/gemxql/index.d.ts +3 -6
  32. package/dist/esm/core/gemxql/types/date-filter.d.ts +1 -1
  33. package/dist/esm/core/gemxql/types/index.d.ts +0 -2
  34. package/dist/esm/gemxql.js +159 -204
  35. package/dist/esm/gemxql.mjs +159 -204
  36. package/dist/esm/index.d.ts +1 -3
  37. package/dist/esm/index.js +2041 -2080
  38. package/dist/esm/index.mjs +2041 -2080
  39. package/dist/esm/shared/charts/components/GPolarisViz/utilities/getFontSize.d.ts +1 -1
  40. package/dist/esm/shared/components/GTimePicker/GTimePicker.d.ts +1 -1
  41. package/dist/esm/shared/components/GTimePicker/helpers/parse-date.d.ts +2 -2
  42. package/dist/esm/shared/components/GTimePicker/hooks/useCompareDateTimePicker.d.ts +1 -2
  43. package/dist/esm/shared/components/GTimePicker/types/index.d.ts +1 -1
  44. package/dist/esm/shared/components/index.d.ts +0 -1
  45. package/dist/esm/types/breakdown-items.d.ts +19 -0
  46. package/dist/esm/types/index.d.ts +1 -0
  47. package/dist/esm/types.js +24 -1
  48. package/dist/esm/types.mjs +24 -1
  49. package/dist/esm/utils/analytics.d.ts +12 -0
  50. package/dist/esm/utils/dayjs.d.ts +10 -0
  51. package/dist/esm/utils/index.d.ts +2 -0
  52. package/dist/umd/esm/components/GTimePicker/GTimePicker.d.ts +17 -0
  53. package/dist/umd/esm/components/GTimePicker/components/BaseTimePicker.d.ts +10 -0
  54. package/dist/umd/esm/components/GTimePicker/components/CompareTimePicker.d.ts +5 -0
  55. package/dist/umd/esm/components/GTimePicker/components/DateTimeFilterAddition.d.ts +2 -0
  56. package/dist/umd/esm/components/GTimePicker/components/DateTimeFilterInputs.d.ts +9 -0
  57. package/dist/umd/esm/components/GTimePicker/components/DateTimeFilters.d.ts +15 -0
  58. package/dist/umd/esm/components/GTimePicker/components/MainTimePicker.d.ts +3 -0
  59. package/dist/umd/esm/components/GTimePicker/components/index.d.ts +2 -0
  60. package/dist/umd/esm/components/GTimePicker/constants/compareDateTimePicker.d.ts +12 -0
  61. package/dist/umd/esm/components/GTimePicker/constants/datePicker.d.ts +14 -0
  62. package/dist/umd/esm/components/GTimePicker/constants/index.d.ts +2 -0
  63. package/dist/umd/esm/components/GTimePicker/constants/mainDataTimePicker.d.ts +14 -0
  64. package/dist/umd/esm/components/GTimePicker/contexts/DateTimePickerProvider.d.ts +15 -0
  65. package/dist/umd/esm/components/GTimePicker/contexts/index.d.ts +1 -0
  66. package/dist/umd/esm/components/GTimePicker/helpers/date-range-info.d.ts +16 -0
  67. package/dist/umd/esm/components/GTimePicker/helpers/index.d.ts +4 -0
  68. package/dist/umd/esm/components/GTimePicker/helpers/parse-date.d.ts +24 -0
  69. package/dist/umd/esm/components/GTimePicker/helpers/time-picker.d.ts +76 -0
  70. package/dist/umd/esm/components/GTimePicker/helpers/version.d.ts +2 -0
  71. package/dist/umd/esm/components/GTimePicker/hooks/index.d.ts +3 -0
  72. package/dist/umd/esm/components/GTimePicker/hooks/useCompareDateTimePicker.d.ts +25 -0
  73. package/dist/umd/esm/components/GTimePicker/hooks/useDateTimeFilter.d.ts +18 -0
  74. package/dist/umd/esm/components/GTimePicker/hooks/useDateTimePicker.d.ts +30 -0
  75. package/dist/umd/esm/components/GTimePicker/hooks/useVersionDateTimeFilters.d.ts +9 -0
  76. package/dist/umd/esm/components/GTimePicker/index.d.ts +7 -0
  77. package/dist/umd/esm/components/GTimePicker/types/index.d.ts +38 -0
  78. package/dist/umd/esm/components/index.d.ts +1 -0
  79. package/dist/umd/esm/constants/breakdown-targets.d.ts +1 -1
  80. package/dist/umd/esm/core/gemxql/builder/clauses/mode-query.d.ts +1 -1
  81. package/dist/umd/esm/core/gemxql/helpers/getTimeDimension.d.ts +1 -1
  82. package/dist/umd/esm/core/gemxql/index.d.ts +3 -6
  83. package/dist/umd/esm/core/gemxql/types/date-filter.d.ts +1 -1
  84. package/dist/umd/esm/core/gemxql/types/index.d.ts +0 -2
  85. package/dist/umd/esm/index.d.ts +1 -3
  86. package/dist/umd/esm/shared/charts/components/GPolarisViz/utilities/getFontSize.d.ts +1 -1
  87. package/dist/umd/esm/shared/components/GTimePicker/GTimePicker.d.ts +1 -1
  88. package/dist/umd/esm/shared/components/GTimePicker/helpers/parse-date.d.ts +2 -2
  89. package/dist/umd/esm/shared/components/GTimePicker/hooks/useCompareDateTimePicker.d.ts +1 -2
  90. package/dist/umd/esm/shared/components/GTimePicker/types/index.d.ts +1 -1
  91. package/dist/umd/esm/shared/components/index.d.ts +0 -1
  92. package/dist/umd/esm/types/breakdown-items.d.ts +19 -0
  93. package/dist/umd/esm/types/index.d.ts +1 -0
  94. package/dist/umd/esm/utils/analytics.d.ts +12 -0
  95. package/dist/umd/esm/utils/dayjs.d.ts +10 -0
  96. package/dist/umd/esm/utils/index.d.ts +2 -0
  97. package/dist/umd/gemxql.js +1 -1
  98. package/dist/umd/index.js +1 -1
  99. package/dist/umd/types.js +1 -1
  100. package/package.json +1 -1
@@ -1,14 +1,15 @@
1
1
  "use client"
2
2
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
3
- import '@tanstack/react-query';
3
+ 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';
4
+ import React, { useMemo, useCallback, useState, useEffect, forwardRef, Fragment as Fragment$1, useRef, useImperativeHandle, createContext, useContext } from 'react';
4
5
  import dayjs from 'dayjs';
6
+ export { default as dayjs } from 'dayjs';
5
7
  import quarterOfYear from 'dayjs/plugin/quarterOfYear.js';
6
8
  import timezone from 'dayjs/plugin/timezone.js';
7
9
  import utc from 'dayjs/plugin/utc.js';
8
- 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
10
  import { useTranslation } from 'react-i18next';
11
11
  import { PolarisVizProvider, LineChart, DonutChart } from '@shopify/polaris-viz';
12
+ import '@tanstack/react-query';
12
13
 
13
14
  var EMetricKey;
14
15
  (function (EMetricKey) {
@@ -124,53 +125,12 @@ const ANALYTICS_METRIC_TOOLTIP = {
124
125
  },
125
126
  };
126
127
 
127
- const NONE_VALUE = 'None';
128
- const PLACEHOLDER_VALUE$1 = '-';
129
-
130
- const TOTALS_SUFFIX = '___totals';
131
- const COMPARE_PREFIX = 'comparison___';
132
- const COMPARE_SUFFIX = '___previous_period';
133
- const COMPARE_TOTALS_SUFFIX = `${COMPARE_SUFFIX}${TOTALS_SUFFIX}`;
134
-
135
- const OPERATOR_IS = 'is';
136
-
137
- var EAnalyticDataType;
138
- (function (EAnalyticDataType) {
139
- EAnalyticDataType["DATE"] = "DATE";
140
- EAnalyticDataType["ARRAY"] = "ARRAY";
141
- EAnalyticDataType["OBJECT"] = "OBJECT";
142
- EAnalyticDataType["STRING"] = "STRING";
143
- EAnalyticDataType["INTEGER"] = "INTEGER";
144
- EAnalyticDataType["CURRENCY"] = "CURRENCY";
145
- EAnalyticDataType["PERCENT"] = "PERCENT";
146
- EAnalyticDataType["DURATION"] = "DURATION";
147
- EAnalyticDataType["MONTH"] = "MONTH_TIMESTAMP";
148
- EAnalyticDataType["QUARTER"] = "QUARTER_TIMESTAMP";
149
- EAnalyticDataType["DAY"] = "DAY_TIMESTAMP";
150
- EAnalyticDataType["WEEK"] = "WEEK_TIMESTAMP";
151
- EAnalyticDataType["YEAR"] = "YEAR_TIMESTAMP";
152
- EAnalyticDataType["HOUR"] = "HOUR_TIMESTAMP";
153
- })(EAnalyticDataType || (EAnalyticDataType = {}));
154
- var EAnalyticColumnKey;
155
- (function (EAnalyticColumnKey) {
156
- EAnalyticColumnKey["CAMPAIGNS"] = "experiments";
157
- EAnalyticColumnKey["VISITOR_ITEMS"] = "visitor_items";
158
- EAnalyticColumnKey["DEVICE_ITEMS"] = "device_items";
159
- EAnalyticColumnKey["TRAFFIC_SOURCE_ITEMS"] = "traffic_source_items";
160
- })(EAnalyticColumnKey || (EAnalyticColumnKey = {}));
161
-
162
- var EAnalyticMode$1;
128
+ var EAnalyticMode;
163
129
  (function (EAnalyticMode) {
164
130
  EAnalyticMode["ALL_SESSION"] = "ALL_SESSION";
165
131
  EAnalyticMode["FIRST_SESSION"] = "FIRST_SESSION";
166
132
  EAnalyticMode["PAGE_ONLY"] = "PAGE_ONLY";
167
- })(EAnalyticMode$1 || (EAnalyticMode$1 = {}));
168
-
169
- var EAnalyticSource;
170
- (function (EAnalyticSource) {
171
- EAnalyticSource["SESSIONS"] = "sessions";
172
- EAnalyticSource["SALES"] = "sales";
173
- })(EAnalyticSource || (EAnalyticSource = {}));
133
+ })(EAnalyticMode || (EAnalyticMode = {}));
174
134
 
175
135
  var EVisitorType;
176
136
  (function (EVisitorType) {
@@ -195,182 +155,108 @@ var ETrafficSourceType;
195
155
  ETrafficSourceType["SMS"] = "sms";
196
156
  })(ETrafficSourceType || (ETrafficSourceType = {}));
197
157
 
198
- var EComparisonOperator;
199
- (function (EComparisonOperator) {
200
- EComparisonOperator["EQ"] = "=";
201
- EComparisonOperator["IN"] = "IN";
202
- EComparisonOperator["LIKE"] = "LIKE";
203
- })(EComparisonOperator || (EComparisonOperator = {}));
204
- var EGroupOperator;
205
- (function (EGroupOperator) {
206
- EGroupOperator["OR"] = "OR";
207
- EGroupOperator["AND"] = "AND";
208
- })(EGroupOperator || (EGroupOperator = {}));
158
+ const TARGET_VISITOR = [
159
+ { value: EVisitorType.NEW, label: 'New' },
160
+ { value: EVisitorType.RETURNING, label: 'Returning' },
161
+ ];
162
+ const TARGET_DEVICES = [
163
+ { value: EDeviceType.DESKTOP, label: 'Desktop' },
164
+ { value: EDeviceType.TABLET, label: 'Tablet' },
165
+ { value: EDeviceType.MOBILE, label: 'Mobile' },
166
+ ];
167
+ const TARGET_CHANNEL = [
168
+ { value: ETrafficSourceType.DIRECT, label: 'Direct' },
169
+ { value: ETrafficSourceType.EMAIL, label: 'Email' },
170
+ { value: ETrafficSourceType.REFERRAL, label: 'Referral' },
171
+ { value: ETrafficSourceType.ORGANIC_SOCIAL, label: 'Organic social' },
172
+ { value: ETrafficSourceType.ORGANIC_SEARCH, label: 'Organic search' },
173
+ { value: ETrafficSourceType.PAID_SOCIAL, label: 'Paid social' },
174
+ { value: ETrafficSourceType.PAID_SEARCH, label: 'Paid search' },
175
+ { value: ETrafficSourceType.SMS, label: 'SMS' },
176
+ ];
209
177
 
210
- var EFilterField;
211
- (function (EFilterField) {
212
- EFilterField["DEVICE"] = "device";
213
- EFilterField["DEVICES"] = "devices";
214
- EFilterField["VISITOR"] = "visitor_type";
215
- EFilterField["VISITORS"] = "visitor_types";
216
- EFilterField["TRAFFIC_SOURCE"] = "traffic_source";
217
- EFilterField["TRAFFIC_SOURCES"] = "traffic_sources";
218
- EFilterField["VERSION"] = "version";
219
- EFilterField["VERSIONS"] = "versions";
220
- EFilterField["SINGLE_PAGE"] = "page_path";
221
- EFilterField["LIST_PAGE"] = "page_paths";
222
- EFilterField["GROUP_CAMPAIGN_ITEM"] = "group_campaign_item";
223
- EFilterField["GROUP_CAMPAIGN_ITEMS"] = "group_campaign_items";
224
- EFilterField["SINGLE_CAMPAIGN"] = "experiment_id";
225
- EFilterField["GROUP_CAMPAIGN"] = "experiment_group_id";
226
- EFilterField["CAMPAIGN_VERSION_ID"] = "version_id";
227
- EFilterField["GROUP_CAMPAIGN_VERSION_ID"] = "group_version_id";
228
- })(EFilterField || (EFilterField = {}));
178
+ const CAMPAIGN_BACKGROUND_MAIN = {
179
+ ORIGIN: '#2C7DFF',
180
+ VARIANT: '#F34A70',
181
+ };
229
182
 
230
- var EOperatorField;
231
- (function (EOperatorField) {
232
- EOperatorField["DEVICE_OPERATOR"] = "deviceOperator";
233
- EOperatorField["VISITOR_OPERATOR"] = "visitorOperator";
234
- EOperatorField["TRAFFIC_SOURCE_OPERATOR"] = "trafficSourceOperator";
235
- EOperatorField["VERSION_OPERATOR"] = "versionOperator";
236
- EOperatorField["PAGE_OPERATOR"] = "pageOperator";
237
- EOperatorField["CAMPAIGN_ITEM_OPERATOR"] = "campaignItemOperator";
238
- })(EOperatorField || (EOperatorField = {}));
183
+ const DEFAULT_CURRENT_PERIOD_LABEL = 'Current';
184
+ const DEFAULT_PREVIOUS_PERIOD_LABEL = 'Previous';
185
+ const CHART_MIN_HEIGHT = 228;
186
+ const SERIES_COLORS = {
187
+ current: 'rgba(64, 176, 230, 1)',
188
+ comparison: 'rgba(161, 202, 231, 1)',
189
+ all: ['#2C7DFF', '#F34A70'],
190
+ };
191
+ const TREND_TONE = {
192
+ POSITIVE: '#007F5F',
193
+ NEUTRAL: '#4A4A4A',
194
+ };
195
+ const PLACEHOLDER_VALUE$1 = '-';
239
196
 
240
- /**
241
- * Controls which totals columns are appended to the query result.
242
- *
243
- * - NONE → no totals, GROUP BY only.
244
- * - TOTALS → adds `<metric>___totals` (grand total only). Use with single-dimension GROUP BY.
245
- * - ALL → adds subtotals per dimension group + grand total. Use with multi-dimension GROUP BY.
246
- */
247
- var EGroupWithClause;
248
- (function (EGroupWithClause) {
249
- EGroupWithClause["NONE"] = "";
250
- EGroupWithClause["TOTALS"] = "TOTALS";
251
- EGroupWithClause["ALL"] = "WITH GROUP_TOTALS, TOTALS";
252
- })(EGroupWithClause || (EGroupWithClause = {}));
197
+ const DEFAULT_CURRENCY_ANALYTIC = 'USD';
253
198
 
254
- var EOrderDirectionType;
255
- (function (EOrderDirectionType) {
256
- EOrderDirectionType["ASC"] = "ASC";
257
- EOrderDirectionType["DESC"] = "DESC";
258
- })(EOrderDirectionType || (EOrderDirectionType = {}));
199
+ var THUMB_PRODUCT_DEFAULT = "data:image/svg+xml;base64,PHN2ZwogIHdpZHRoPSI5MCIKICBoZWlnaHQ9IjcyIgogIHZpZXdCb3g9IjAgMCA5MCA3MiIKICBmaWxsPSJub25lIgogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKPgogIDxwYXRoCiAgICBkPSJNNDguNzUgMzQuNUM0OS45OTI2IDM0LjUgNTEgMzMuNDkyNiA1MSAzMi4yNUM1MSAzMS4wMDc0IDQ5Ljk5MjYgMzAgNDguNzUgMzBDNDcuNTA3NCAzMCA0Ni41IDMxLjAwNzQgNDYuNSAzMi4yNUM0Ni41IDMzLjQ5MjYgNDcuNTA3NCAzNC41IDQ4Ljc1IDM0LjVaIgogICAgZmlsbD0iIzYxNjE2MSIKICAvPgogIDxwYXRoCiAgICBmaWxsUnVsZT0iZXZlbm9kZCIKICAgIGNsaXBSdWxlPSJldmVub2RkIgogICAgZD0iTTQzLjUyNjggMjYuMjVINDYuNDczMkM0Ny42OTI0IDI2LjI1IDQ4LjY3NTggMjYuMjUgNDkuNDcyMiAyNi4zMTVDNTAuMjkyMiAyNi4zODIgNTEuMDEyNCAyNi41MjM2IDUxLjY3ODcgMjYuODYzMUM1Mi43MzcxIDI3LjQwMjQgNTMuNTk3NiAyOC4yNjI5IDU0LjEzNjkgMjkuMzIxM0M1NC40NzY0IDI5Ljk4NzYgNTQuNjE4IDMwLjcwNzggNTQuNjg1IDMxLjUyNzhDNTQuNzUgMzIuMzI0MiA1NC43NSAzMy4zMDc2IDU0Ljc1IDM0LjUyNjhWMzcuNDczMkM1NC43NSAzOC42OTI0IDU0Ljc1IDM5LjY3NTggNTQuNjg1IDQwLjQ3MjJDNTQuNjE4IDQxLjI5MjIgNTQuNDc2NCA0Mi4wMTI0IDU0LjEzNjkgNDIuNjc4N0M1My41OTc2IDQzLjczNzEgNTIuNzM3MSA0NC41OTc2IDUxLjY3ODcgNDUuMTM2OUM1MS4wMTI0IDQ1LjQ3NjQgNTAuMjkyMiA0NS42MTggNDkuNDcyMiA0NS42ODVDNDguNjc1OCA0NS43NSA0Ny42OTI0IDQ1Ljc1IDQ2LjQ3MzIgNDUuNzVINDMuNTI2OEM0Mi4zMDc2IDQ1Ljc1IDQxLjMyNDIgNDUuNzUgNDAuNTI3OCA0NS42ODVDMzkuNzA3OCA0NS42MTggMzguOTg3NiA0NS40NzY0IDM4LjMyMTMgNDUuMTM2OUMzNy4yNjI5IDQ0LjU5NzYgMzYuNDAyNCA0My43MzcxIDM1Ljg2MzEgNDIuNjc4N0MzNS41MjM2IDQyLjAxMjQgMzUuMzgyIDQxLjI5MjIgMzUuMzE1IDQwLjQ3MjJDMzUuMjUgMzkuNjc1OCAzNS4yNSAzOC42OTI0IDM1LjI1IDM3LjQ3MzJWMzQuNTI2OEMzNS4yNSAzMy4zMDc2IDM1LjI1IDMyLjMyNDIgMzUuMzE1IDMxLjUyNzhDMzUuMzgyIDMwLjcwNzggMzUuNTIzNiAyOS45ODc2IDM1Ljg2MzEgMjkuMzIxM0MzNi40MDI0IDI4LjI2MjkgMzcuMjYyOSAyNy40MDI0IDM4LjMyMTMgMjYuODYzMUMzOC45ODc2IDI2LjUyMzYgMzkuNzA3OCAyNi4zODIgNDAuNTI3OCAyNi4zMTVDNDEuMzI0MiAyNi4yNSA0Mi4zMDc2IDI2LjI1IDQzLjUyNjggMjYuMjVaTTQwLjcxMSAyOC41NTc2QzQwLjAzMDIgMjguNjEzMiAzOS42MzkxIDI4LjcxNjkgMzkuMzQyOCAyOC44Njc5QzM4LjcwNzcgMjkuMTkxNCAzOC4xOTE0IDI5LjcwNzcgMzcuODY3OSAzMC4zNDI4QzM3LjcxNjkgMzAuNjM5MSAzNy42MTMyIDMxLjAzMDIgMzcuNTU3NiAzMS43MTFDMzcuNTAwOSAzMi40MDUgMzcuNSAzMy4yOTYzIDM3LjUgMzQuNTc1VjM2LjcxNzdMMzguNTg0MiAzNS40MTY3QzM5LjU3MjQgMzQuMjMwOSA0MS4zNjU1IDM0LjE0OTYgNDIuNDU2OSAzNS4yNDFMNDYuNSAzOS4yODQxTDQ4LjI2OTQgMzcuNTE0NkM0OS4zNzU3IDM2LjQwODMgNTEuMTk4IDM2LjUwOTMgNTIuMTc1NCAzNy43MzA5TDUyLjQ5OTUgMzguMTM2MUM1Mi41IDM3LjkxMzEgNTIuNSAzNy42NzY1IDUyLjUgMzcuNDI1VjM0LjU3NUM1Mi41IDMzLjI5NjMgNTIuNDk5MSAzMi40MDUgNTIuNDQyNCAzMS43MTFDNTIuMzg2OCAzMS4wMzAyIDUyLjI4MzEgMzAuNjM5MSA1Mi4xMzIxIDMwLjM0MjhDNTEuODA4NiAyOS43MDc3IDUxLjI5MjMgMjkuMTkxNCA1MC42NTcyIDI4Ljg2NzlDNTAuMzYwOSAyOC43MTY5IDQ5Ljk2OTggMjguNjEzMiA0OS4yODkgMjguNTU3NkM0OC41OTUgMjguNTAwOSA0Ny43MDM3IDI4LjUgNDYuNDI1IDI4LjVINDMuNTc1QzQyLjI5NjMgMjguNSA0MS40MDUgMjguNTAwOSA0MC43MTEgMjguNTU3NlpNMzcuNTU3NiA0MC4yODlDMzcuNTU0MyA0MC4yNDkyIDM3LjU1MTMgNDAuMjA4OCAzNy41NDg0IDQwLjE2NzhDMzcuNTcxMSA0MC4xNDQ4IDM3LjU5MzEgNDAuMTIwNiAzNy42MTQyIDQwLjA5NTNMNDAuMzEyNyAzNi44NTcxQzQwLjQ1MzkgMzYuNjg3NyA0MC43MSAzNi42NzYxIDQwLjg2NTkgMzYuODMyTDQ1LjcwNDUgNDEuNjcwNkM0Ni4xNDM4IDQyLjEwOTkgNDYuODU2MSA0Mi4xMDk5IDQ3LjI5NTUgNDEuNjcwNkw0OS44NjA0IDM5LjEwNTZDNTAuMDE4NSAzOC45NDc2IDUwLjI3ODggMzguOTYyIDUwLjQxODQgMzkuMTM2NUw1Mi4yMzc3IDQxLjQxMDdDNTIuMjA1NiA0MS41MDEgNTIuMTcwNCA0MS41ODIyIDUyLjEzMjEgNDEuNjU3MkM1MS44MDg2IDQyLjI5MjMgNTEuMjkyMyA0Mi44MDg2IDUwLjY1NzIgNDMuMTMyMUM1MC4zNjA5IDQzLjI4MzEgNDkuOTY5OCA0My4zODY4IDQ5LjI4OSA0My40NDI0QzQ4LjU5NSA0My40OTkxIDQ3LjcwMzcgNDMuNSA0Ni40MjUgNDMuNUg0My41NzVDNDIuMjk2MyA0My41IDQxLjQwNSA0My40OTkxIDQwLjcxMSA0My40NDI0QzQwLjAzMDIgNDMuMzg2OCAzOS42MzkxIDQzLjI4MzEgMzkuMzQyOCA0My4xMzIxQzM4LjcwNzcgNDIuODA4NiAzOC4xOTE0IDQyLjI5MjMgMzcuODY3OSA0MS42NTcyQzM3LjcxNjkgNDEuMzYwOSAzNy42MTMyIDQwLjk2OTggMzcuNTU3NiA0MC4yODlaIgogICAgZmlsbD0iIzYxNjE2MSIKICAvPgo8L3N2Zz4K";
259
200
 
260
- var EPageMetric;
261
- (function (EPageMetric) {
262
- EPageMetric["PAGE_ITEMS"] = "page_items";
263
- EPageMetric["PAGE_PATHS"] = "page_paths";
264
- })(EPageMetric || (EPageMetric = {}));
265
- var EPageDimension;
266
- (function (EPageDimension) {
267
- EPageDimension["PAGE_PATH"] = "page_path";
268
- })(EPageDimension || (EPageDimension = {}));
269
- var EPageField;
270
- (function (EPageField) {
271
- EPageField["SHOPIFY_PAGE_ID"] = "shopify_page_id";
272
- EPageField["LOCATION_PATH"] = "location_path";
273
- EPageField["PAGE_TYPE"] = "page_type";
274
- EPageField["PAGE_TITLE"] = "page_title";
275
- EPageField["PAGE_PATH"] = "page_path";
276
- EPageField["TEMPLATE_SUFFIX"] = "template_suffix";
277
- })(EPageField || (EPageField = {}));
201
+ var SvgArrowRightIcon = function SvgArrowRightIcon(props) {
202
+ return /*#__PURE__*/React.createElement("svg", Object.assign({
203
+ viewBox: "0 0 20 20"
204
+ }, props), /*#__PURE__*/React.createElement("path", {
205
+ fillRule: "evenodd",
206
+ d: "M3.5 10a.75.75 0 0 1 .75-.75h9.69l-2.72-2.72a.75.75 0 1 1 1.06-1.06l4 4a.75.75 0 0 1 0 1.06l-4 4a.75.75 0 0 1-1.06-1.06l2.72-2.72h-9.69a.75.75 0 0 1-.75-.75Z"
207
+ }));
208
+ };
209
+ SvgArrowRightIcon.displayName = "ArrowRightIcon";
278
210
 
279
- var ERowReaderMode;
280
- (function (ERowReaderMode) {
281
- ERowReaderMode["DEFAULT"] = "DEFAULT";
282
- ERowReaderMode["COMPARISON"] = "COMPARISON";
283
- ERowReaderMode["TOTALS"] = "TOTALS";
284
- ERowReaderMode["COMPARISON_TOTALS"] = "COMPARISON_TOTALS";
285
- })(ERowReaderMode || (ERowReaderMode = {}));
211
+ var SvgCalendarIcon = function SvgCalendarIcon(props) {
212
+ return /*#__PURE__*/React.createElement("svg", Object.assign({
213
+ viewBox: "0 0 20 20"
214
+ }, props), /*#__PURE__*/React.createElement("path", {
215
+ fillRule: "evenodd",
216
+ d: "M7.75 3.5a.75.75 0 0 0-1.5 0v.407a3.075 3.075 0 0 0-.702.252 3.75 3.75 0 0 0-1.64 1.639c-.226.444-.32.924-.365 1.47-.043.531-.043 1.187-.043 2v1.464c0 .813 0 1.469.043 2 .045.546.14 1.026.366 1.47a3.75 3.75 0 0 0 1.639 1.64c.444.226.924.32 1.47.365.531.043 1.187.043 2 .043h3.383c.323 0 .542 0 .735-.02a3.75 3.75 0 0 0 3.344-3.344c.02-.193.02-.412.02-.735v-2.883c0-.813 0-1.469-.043-2-.045-.546-.14-1.026-.366-1.47a3.75 3.75 0 0 0-1.639-1.64 3.076 3.076 0 0 0-.702-.251v-.407a.75.75 0 0 0-1.5 0v.259c-.373-.009-.794-.009-1.268-.009h-1.964c-.474 0-.895 0-1.268.009v-.259Zm-1.521 1.995c.197-.1.458-.17.912-.207.462-.037 1.057-.038 1.909-.038h1.9c.853 0 1.447 0 1.91.038.453.037.714.107.912.207.423.216.767.56.983.984.1.197.17.458.207.912.014.18.024.38.029.609h-9.982c.006-.228.015-.429.03-.61.036-.453.106-.714.206-.911a2.25 2.25 0 0 1 .984-.984Zm-1.229 4.005v1.2c0 .853 0 1.447.038 1.91.037.453.107.714.207.912.216.423.56.767.984.983.197.1.458.17.912.207.462.037 1.057.038 1.909.038h3.306c.385 0 .52-.001.626-.012a2.25 2.25 0 0 0 2.006-2.006c.011-.106.012-.241.012-.626v-2.606h-10Z"
217
+ }));
218
+ };
219
+ SvgCalendarIcon.displayName = "CalendarIcon";
286
220
 
287
- var ETimeDimension;
288
- (function (ETimeDimension) {
289
- ETimeDimension["HOUR"] = "hour";
290
- ETimeDimension["DAY"] = "day";
291
- ETimeDimension["WEEK"] = "week";
292
- ETimeDimension["MONTH"] = "month";
293
- ETimeDimension["QUARTER"] = "quarter";
294
- ETimeDimension["YEAR"] = "year";
295
- })(ETimeDimension || (ETimeDimension = {}));
221
+ var SvgCheckIcon = function SvgCheckIcon(props) {
222
+ return /*#__PURE__*/React.createElement("svg", Object.assign({
223
+ viewBox: "0 0 20 20"
224
+ }, props), /*#__PURE__*/React.createElement("path", {
225
+ fillRule: "evenodd",
226
+ d: "M15.78 5.97a.75.75 0 0 1 0 1.06l-6.5 6.5a.75.75 0 0 1-1.06 0l-3.25-3.25a.75.75 0 1 1 1.06-1.06l2.72 2.72 5.97-5.97a.75.75 0 0 1 1.06 0Z"
227
+ }));
228
+ };
229
+ SvgCheckIcon.displayName = "CheckIcon";
296
230
 
297
- ({
298
- [ERowReaderMode.DEFAULT]: { prefix: '', suffix: '' },
299
- [ERowReaderMode.COMPARISON]: { prefix: COMPARE_PREFIX, suffix: COMPARE_SUFFIX },
300
- [ERowReaderMode.TOTALS]: { prefix: '', suffix: TOTALS_SUFFIX },
301
- [ERowReaderMode.COMPARISON_TOTALS]: { prefix: COMPARE_PREFIX, suffix: COMPARE_TOTALS_SUFFIX },
302
- });
231
+ var SvgChevronDownIcon = function SvgChevronDownIcon(props) {
232
+ return /*#__PURE__*/React.createElement("svg", Object.assign({
233
+ viewBox: "0 0 20 20"
234
+ }, props), /*#__PURE__*/React.createElement("path", {
235
+ fillRule: "evenodd",
236
+ d: "M5.72 8.47a.75.75 0 0 1 1.06 0l3.47 3.47 3.47-3.47a.75.75 0 1 1 1.06 1.06l-4 4a.75.75 0 0 1-1.06 0l-4-4a.75.75 0 0 1 0-1.06Z"
237
+ }));
238
+ };
239
+ SvgChevronDownIcon.displayName = "ChevronDownIcon";
303
240
 
304
- EGroupOperator.OR;
241
+ var SvgChevronRightIcon = function SvgChevronRightIcon(props) {
242
+ return /*#__PURE__*/React.createElement("svg", Object.assign({
243
+ viewBox: "0 0 20 20"
244
+ }, props), /*#__PURE__*/React.createElement("path", {
245
+ fillRule: "evenodd",
246
+ d: "M7.72 14.53a.75.75 0 0 1 0-1.06l3.47-3.47-3.47-3.47a.75.75 0 0 1 1.06-1.06l4 4a.75.75 0 0 1 0 1.06l-4 4a.75.75 0 0 1-1.06 0Z"
247
+ }));
248
+ };
249
+ SvgChevronRightIcon.displayName = "ChevronRightIcon";
305
250
 
306
- [
307
- {
308
- operator: EOperatorField.DEVICE_OPERATOR,
309
- singleField: EFilterField.DEVICE,
310
- multiField: EFilterField.DEVICES,
311
- fieldName: EFilterField.DEVICE,
312
- },
313
- {
314
- operator: EOperatorField.VISITOR_OPERATOR,
315
- singleField: EFilterField.VISITOR,
316
- multiField: EFilterField.VISITORS,
317
- fieldName: EFilterField.VISITOR,
318
- },
319
- {
320
- operator: EOperatorField.TRAFFIC_SOURCE_OPERATOR,
321
- singleField: EFilterField.TRAFFIC_SOURCE,
322
- multiField: EFilterField.TRAFFIC_SOURCES,
323
- fieldName: EFilterField.TRAFFIC_SOURCE,
324
- },
325
- {
326
- operator: EOperatorField.VERSION_OPERATOR,
327
- singleField: EFilterField.VERSION,
328
- multiField: EFilterField.VERSIONS,
329
- fieldName: EFilterField.VERSION,
330
- },
331
- {
332
- operator: EOperatorField.PAGE_OPERATOR,
333
- singleField: EFilterField.SINGLE_PAGE,
334
- multiField: EFilterField.LIST_PAGE,
335
- fieldName: EFilterField.SINGLE_PAGE,
336
- },
337
- {
338
- operator: EOperatorField.CAMPAIGN_ITEM_OPERATOR,
339
- singleField: EFilterField.GROUP_CAMPAIGN_ITEM,
340
- multiField: EFilterField.GROUP_CAMPAIGN_ITEMS,
341
- condition: EFilterField.GROUP_CAMPAIGN,
342
- fieldName: EFilterField.SINGLE_CAMPAIGN,
343
- },
344
- {
345
- operatorVal: OPERATOR_IS,
346
- singleField: EFilterField.SINGLE_CAMPAIGN,
347
- multiField: EFilterField.GROUP_CAMPAIGN,
348
- },
349
- ];
350
-
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();
251
+ var SvgChevronUpIcon = function SvgChevronUpIcon(props) {
252
+ return /*#__PURE__*/React.createElement("svg", Object.assign({
253
+ viewBox: "0 0 20 20"
254
+ }, props), /*#__PURE__*/React.createElement("path", {
255
+ fillRule: "evenodd",
256
+ d: "M14.53 12.28a.75.75 0 0 1-1.06 0l-3.47-3.47-3.47 3.47a.75.75 0 0 1-1.06-1.06l4-4a.75.75 0 0 1 1.06 0l4 4a.75.75 0 0 1 0 1.06Z"
257
+ }));
373
258
  };
259
+ SvgChevronUpIcon.displayName = "ChevronUpIcon";
374
260
 
375
261
  const TRIM_DECIMAL_ZEROS_REGEX = /\.0+$/;
376
262
  const DEFAULT_DECIMALS = 2;
@@ -384,6 +270,9 @@ const semverToNum = (v) => {
384
270
  const [major, minor, patch] = v.split('.').map((n) => Number(n));
385
271
  return (major ?? 0) * 1_000_000 + (minor ?? 0) * 1_000 + (patch ?? 0);
386
272
  };
273
+ const numberWithCommas = (x) => {
274
+ return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
275
+ };
387
276
 
388
277
  /**
389
278
  * Utility function to calculate percentage and format it.
@@ -419,6 +308,118 @@ const formatPercentage = (percentage, decimals = DEFAULT_DECIMALS) => {
419
308
  return `${cleanDecimal(percentage, decimals)}%`;
420
309
  };
421
310
 
311
+ function toVal(mix) {
312
+ if (typeof mix === 'string') {
313
+ return mix;
314
+ }
315
+ else if (typeof mix === 'object' && mix !== null) {
316
+ return Object.keys(mix)
317
+ .filter((key) => mix[key])
318
+ .join(' ');
319
+ }
320
+ else {
321
+ return false;
322
+ }
323
+ }
324
+ function cls(...classes) {
325
+ return classes.map(toVal).filter(Boolean).join(' ');
326
+ }
327
+
328
+ function compareValues(a, b, order = 'asc') {
329
+ if (a === b)
330
+ return 0;
331
+ if (a === undefined || b === undefined) {
332
+ if (a === undefined && b !== undefined)
333
+ return order === 'asc' ? -1 : 1;
334
+ if (b === undefined && a !== undefined)
335
+ return order === 'asc' ? 1 : -1;
336
+ return 0;
337
+ }
338
+ const isDate = (val) => typeof val !== 'boolean' && !isNaN(Date.parse(val));
339
+ const isString = (val) => typeof val === 'string';
340
+ let comparison = 0;
341
+ if (isDate(a) && isDate(b)) {
342
+ const dateA = a instanceof Date ? a : new Date(a);
343
+ const dateB = b instanceof Date ? b : new Date(b);
344
+ comparison = dateA > dateB ? 1 : -1;
345
+ }
346
+ else if (isString(a) && isString(b)) {
347
+ comparison = a > b ? 1 : -1;
348
+ }
349
+ else {
350
+ comparison = a > b ? 1 : -1;
351
+ }
352
+ return order === 'asc' ? -comparison : comparison;
353
+ }
354
+ function getNestedValue(obj, path) {
355
+ if (typeof path === 'string') {
356
+ return path
357
+ .replace(/\[(\d+)\]/g, '.$1')
358
+ .split('.')
359
+ .reduce((acc, key) => acc?.[key], obj);
360
+ }
361
+ return obj[path];
362
+ }
363
+ function sortByCondition(array, options) {
364
+ const { attr, order = 'asc', preferredValue, backupAttr, orderArrayAttr, orderArray } = options;
365
+ return array.slice().sort((a, b) => {
366
+ const valueA = getNestedValue(a, attr);
367
+ const valueB = getNestedValue(b, attr);
368
+ if (preferredValue !== undefined) {
369
+ if (valueA === preferredValue && valueB !== preferredValue)
370
+ return -1;
371
+ if (valueB === preferredValue && valueA !== preferredValue)
372
+ return 1;
373
+ }
374
+ if (orderArrayAttr === attr && orderArray) {
375
+ const orderArrayValue = orderArray[order];
376
+ return orderArrayValue.indexOf(valueA) - orderArrayValue.indexOf(valueB);
377
+ }
378
+ const primaryComparison = compareValues(valueA, valueB, order);
379
+ if (primaryComparison !== 0)
380
+ return primaryComparison;
381
+ if (backupAttr)
382
+ return compareValues(a[backupAttr], b[backupAttr], order);
383
+ return 0;
384
+ });
385
+ }
386
+ function sortByConditions(array, optionsArray) {
387
+ return optionsArray.reduce((sortedArray, options) => {
388
+ return sortByCondition(sortedArray, options);
389
+ }, array.slice());
390
+ }
391
+
392
+ dayjs.extend(utc);
393
+ dayjs.extend(timezone);
394
+ dayjs.extend(quarterOfYear);
395
+ let tz = 'UTC';
396
+ const DEFAULT_DATE_FORMAT = 'YYYY-MM-DD HH:mm:ss';
397
+ function getInitialTimezone() {
398
+ return tz;
399
+ }
400
+ function setTz(value) {
401
+ tz = value;
402
+ dayjs.tz.setDefault(value);
403
+ }
404
+ const dayjsTz = (date) => {
405
+ if (!date)
406
+ return dayjs().tz(tz);
407
+ return dayjs(date).tz(tz);
408
+ };
409
+ const convertDateToTz = (date) => {
410
+ if (!date)
411
+ return dayjs.tz(dayjs().format(DEFAULT_DATE_FORMAT), tz);
412
+ return dayjs.tz(dayjs(date).format(DEFAULT_DATE_FORMAT), tz);
413
+ };
414
+ const dayjsTzToLocalTZ = (date) => {
415
+ if (!date)
416
+ return dayjs(dayjsTz().format(DEFAULT_DATE_FORMAT));
417
+ return dayjs(dayjsTz(date).format(DEFAULT_DATE_FORMAT));
418
+ };
419
+ const dayjsTzToDate = (date) => {
420
+ return dayjsTzToLocalTZ(date).toDate();
421
+ };
422
+
422
423
  var AnalyticInterval;
423
424
  (function (AnalyticInterval) {
424
425
  AnalyticInterval["DAY"] = "DAY";
@@ -428,9 +429,6 @@ var AnalyticInterval;
428
429
  AnalyticInterval["WEEK"] = "WEEK";
429
430
  AnalyticInterval["YEAR"] = "YEAR";
430
431
  })(AnalyticInterval || (AnalyticInterval = {}));
431
- function numberWithCommas(x) {
432
- return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
433
- }
434
432
  const SECONDS_IN_MINUTE = 60;
435
433
  const SECONDS_IN_HOUR = SECONDS_IN_MINUTE * SECONDS_IN_MINUTE;
436
434
  const getTimeDurationLabel = (valueInSeconds) => {
@@ -488,675 +486,1076 @@ const getFormattedByInterval = (value, interval, options) => {
488
486
  return dayjsTz(value).format(optionFormat.formatMonth);
489
487
  };
490
488
 
491
- const formatAnalyticDate = (dateString) => {
492
- if (!dateString)
493
- return 'None';
494
- const date = dayjsTz(dateString);
495
- const now = dayjsTz();
496
- const yesterday = dayjsTz().subtract(1, 'day');
497
- const isToday = date.format('YYYY-MM-DD') === now.format('YYYY-MM-DD');
498
- const isYesterday = date.format('YYYY-MM-DD') === yesterday.format('YYYY-MM-DD');
499
- if (isToday) {
500
- return `Today at ${date.format('HH:mm')}`;
501
- }
502
- if (isYesterday) {
503
- return `Yesterday at ${date.format('HH:mm')}`;
504
- }
505
- const daysDiff = now.diff(date, 'day');
506
- const isWithinWeek = daysDiff >= 0 && daysDiff < 7;
507
- if (isWithinWeek) {
508
- return `${date.format('dddd')} at ${date.format('HH:mm')}`;
509
- }
510
- return `${date.format('MMM D')} at ${date.format('hh:mm a')}`;
489
+ const GClickable = ({ children, fullWidth = false, cursor = 'pointer', onClick, onMouseEnter, onMouseLeave, }) => {
490
+ return (jsx("div", { role: "button", tabIndex: 0, className: cls({
491
+ 'w-full': fullWidth,
492
+ 'cursor-pointer': cursor === 'pointer',
493
+ 'cursor-default': cursor === 'default',
494
+ 'cursor-not-allowed': cursor === 'not-allowed',
495
+ }), onKeyDown: (e) => {
496
+ if (e.key === 'Enter' || e.key === ' ') {
497
+ e.preventDefault();
498
+ onClick();
499
+ }
500
+ }, onClick: onClick, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, children: children }));
511
501
  };
512
502
 
513
- const formatAnalyticData = ({ value, formatter, getTextPrice, name, }) => {
514
- const dataTypeIsObjectOrArray = value !== null && (typeof value === 'object' || Array.isArray(value));
515
- if (dataTypeIsObjectOrArray)
516
- return value;
517
- switch (formatter) {
518
- case EAnalyticDataType.INTEGER: {
519
- return numberWithCommas((value ?? 0).toString());
520
- }
521
- case EAnalyticDataType.CURRENCY: {
522
- if (!getTextPrice)
523
- return `${value ?? 0}`;
524
- return getTextPrice(value, false);
525
- }
526
- case EAnalyticDataType.DATE: {
527
- return formatAnalyticDate(value);
528
- }
529
- case EAnalyticDataType.PERCENT: {
530
- if (typeof value !== 'number')
531
- return calcPercentageString(0, 1, 2) ?? '';
532
- return calcPercentageString(value / 100, 1, 2) ?? '';
533
- }
534
- case EAnalyticDataType.DURATION: {
535
- return getTimeDurationLabel(Number(value));
536
- }
537
- case EAnalyticDataType.STRING: {
538
- const fallbackValue = name === EAnalyticColumnKey.CAMPAIGNS ? '' : NONE_VALUE;
539
- return value ?? fallbackValue;
540
- }
541
- case EAnalyticDataType.DAY: {
542
- return getFormattedByInterval(value, AnalyticInterval.DAY, { isExpandDetail: true });
543
- }
544
- case EAnalyticDataType.HOUR: {
545
- return getFormattedByInterval(value, AnalyticInterval.HOUR, { isExpandDetail: true });
546
- }
547
- case EAnalyticDataType.MONTH: {
548
- return getFormattedByInterval(value, AnalyticInterval.MONTH, { isExpandDetail: true });
549
- }
550
- case EAnalyticDataType.YEAR: {
551
- return getFormattedByInterval(value, AnalyticInterval.YEAR);
552
- }
553
- case EAnalyticDataType.WEEK: {
554
- return getFormattedByInterval(value, AnalyticInterval.WEEK, { isExpandDetail: true });
503
+ const GActivatorPopover = ({ onClick, active, content, textProps, boxProps: customBoxProps, disabled, icon: customIcon, }) => {
504
+ const boxProps = useMemo(() => {
505
+ if (disabled) {
506
+ return {
507
+ borderColor: 'border-disabled',
508
+ background: 'bg-surface-disabled',
509
+ ...customBoxProps,
510
+ };
555
511
  }
556
- case EAnalyticDataType.QUARTER: {
557
- return getFormattedByInterval(value, AnalyticInterval.QUARTER, {
558
- isExpandDetail: true,
559
- });
512
+ return {
513
+ shadow: active ? 'button-inset' : 'button',
514
+ background: active ? 'bg-fill-active' : 'bg-fill',
515
+ ...customBoxProps,
516
+ };
517
+ }, [active, disabled, customBoxProps]);
518
+ const toneClass = useMemo(() => {
519
+ if (disabled) {
520
+ return 'text-[var(--p-color-text-disabled)]';
560
521
  }
561
- case EAnalyticDataType.OBJECT:
562
- case EAnalyticDataType.ARRAY: {
563
- return value;
564
- }
565
- default:
566
- return `${value}`;
567
- }
522
+ return active ? 'text-[var(--p-color-text-subdued)]' : 'text-[var(--p-color-text)]';
523
+ }, [active, disabled]);
524
+ const textComponent = useMemo(() => {
525
+ return (jsx(Text, { as: "span", variant: "bodyMd", fontWeight: "medium", tone: disabled ? 'inherit' : textProps?.tone, truncate: true, ...(textProps?.variant && { variant: textProps.variant }), children: content }));
526
+ }, [content, textProps, disabled]);
527
+ const handleClick = useCallback(() => {
528
+ if (disabled)
529
+ return;
530
+ onClick();
531
+ }, [disabled, onClick]);
532
+ return (jsx(GClickable, { cursor: disabled ? 'default' : 'pointer', onClick: handleClick, children: jsx("div", { className: cls(toneClass), children: jsxs(Box, { padding: "150", paddingInline: "300", paddingInlineEnd: "150", borderRadius: "200", ...boxProps, children: [customIcon && (jsxs(InlineStack, { gap: "200", align: "center", wrap: false, children: [jsx(Box, { children: jsx(Icon, { source: customIcon }) }), textComponent] })), !customIcon && (jsxs(InlineGrid, { columns: "1fr 20px", gap: "200", alignItems: "center", children: [textComponent, jsx(Icon, { source: active ? SvgChevronUpIcon : SvgChevronDownIcon })] }))] }) }) }));
568
533
  };
569
534
 
570
- const SESSION_KEY = 'sessions';
571
- const hasMetricData = (metric) => {
572
- const sessions = metric?.[SESSION_KEY];
573
- return typeof sessions === 'number' && sessions > 0;
535
+ const GBlockCenter = ({ height, align, inlineAlign, display, ...props }) => {
536
+ const stickyStyle = useMemo(() => {
537
+ if (props.position !== 'sticky')
538
+ return {};
539
+ const style = {
540
+ position: 'sticky',
541
+ };
542
+ if (props.insetInlineStart)
543
+ style.insetInlineStart = Number(props.insetInlineStart) * 4;
544
+ if (props.insetInlineEnd)
545
+ style.insetInlineEnd = Number(props.insetInlineEnd) * 4;
546
+ if (props.insetBlockStart)
547
+ style.insetBlockStart = Number(props.insetBlockStart) * 4;
548
+ if (props.insetBlockEnd)
549
+ style.insetBlockEnd = Number(props.insetBlockEnd) * 4;
550
+ return style;
551
+ }, [props.position, props.insetInlineStart, props.insetInlineEnd, props.insetBlockStart, props.insetBlockEnd]);
552
+ return (jsx("div", { className: "Polaris-GBlockCenter", style: {
553
+ ...stickyStyle,
554
+ '--gp-block-center-height': height,
555
+ '--gp-block-center-display': display,
556
+ '--gp-block-center-align': align,
557
+ '--gp-block-center-inline-align': inlineAlign,
558
+ '--gp-block-center-overflow-x': props.overflowX,
559
+ '--gp-block-center-overflow-y': props.overflowY,
560
+ }, children: jsx(Box, { ...props }) }));
574
561
  };
575
562
 
576
- const parseRawJson = (raw) => {
577
- if (!raw)
578
- return undefined;
579
- return typeof raw === 'string' ? JSON.parse(raw) : raw;
563
+ const GTooltip = ({ isEnabled = true, content, maxWidth, ...props }) => {
564
+ const hasContent = isEnabled && !!content;
565
+ return hasContent ? (jsx(Tooltip, { width: "wide", hoverDelay: 500, content: content, ...props, accessibilityLabel: maxWidth?.toString() })) : (props.children);
580
566
  };
581
- const parseJsonArray = (raw) => {
582
- try {
583
- const parsed = parseRawJson(raw);
584
- if (!Array.isArray(parsed))
585
- return undefined;
586
- return parsed;
587
- }
588
- catch {
589
- return undefined;
567
+
568
+ const GButton = ({ activatorWrapper, children, iconRight, inset, stopPropagation = true, onClick, themeTone = 'light', variant, ...props }) => {
569
+ const Wrapper = activatorWrapper || 'div';
570
+ const isNeutral = variant === 'neutral';
571
+ const polarisVariant = isNeutral ? undefined : variant;
572
+ const handleClick = (e) => {
573
+ stopPropagation && e.stopPropagation();
574
+ if (props.disabled)
575
+ return;
576
+ onClick?.();
577
+ };
578
+ const button = (jsx(GTooltip, { activatorWrapper: "tooltip-content", ...props.tooltip, children: jsx(Wrapper, { className: cls('Polaris-GButton', {
579
+ 'Polaris-GButton--icon-right': iconRight,
580
+ 'Polaris-GButton--dark': themeTone === 'dark',
581
+ 'Polaris-GButton--neutral': isNeutral,
582
+ 'cursor-default': props.disabled,
583
+ 'Polaris-GButton--fullWidth': props.fullWidth,
584
+ flex: inset,
585
+ }), onClick: handleClick, children: jsx(Button, { variant: polarisVariant, ...props, children: children }) }) }));
586
+ if (inset) {
587
+ return jsx(Box, { padding: "100", children: button });
590
588
  }
589
+ return button;
591
590
  };
592
- const parseBreakdownItems = (raw) => parseJsonArray(raw)?.map((item) => ({ ...item, total: Number(item.total) }));
593
591
 
594
- const readNumeric = (metric, key) => {
595
- const raw = metric?.[key];
596
- return typeof raw === 'number' ? raw : 0;
592
+ const GCheckbox = ({ ...props }) => {
593
+ return props.multiple ? jsx(GCheckboxMultiple, { ...props }) : jsx(GCheckboxSingle, { ...props });
597
594
  };
598
-
599
- const useAnalyticData = (getTextPrice) => {
600
- const formatData = ({ value, formatter, name }) => {
601
- return formatAnalyticData({ value, formatter, getTextPrice, name });
595
+ const GCheckboxMultiple = ({ options, onChange, onChangeSingleValue, emptySelected, selected, onHover, itemHovered, dependentDisabledValues, }) => {
596
+ const [settingOptions, setSettingOptions] = useState([]);
597
+ const handleChange = (value) => {
598
+ if (onChangeSingleValue) {
599
+ onChangeSingleValue(value);
600
+ }
601
+ const updatedOptions = settingOptions.includes(value)
602
+ ? settingOptions.filter((item) => item !== value)
603
+ : [...settingOptions, value];
604
+ setSettingOptions(updatedOptions);
605
+ onChange(updatedOptions);
602
606
  };
603
- const computeMetric = ({ metric, previousMetric, metricKey, formatter, }) => {
604
- if (!hasMetricData(metric))
605
- return { value: 0, change: PLACEHOLDER_VALUE$1 };
606
- const currentValue = readNumeric(metric, metricKey);
607
- const previousValue = readNumeric(previousMetric, metricKey);
608
- const value = formatData({ value: currentValue, formatter, name: metricKey });
609
- if (currentValue === 0 && previousValue !== 0)
610
- return { value, change: -100 };
611
- if (previousValue === 0)
612
- return { value, change: PLACEHOLDER_VALUE$1 };
613
- const change = ((currentValue - previousValue) / previousValue) * 100;
614
- return { value, change };
607
+ const handleHover = (value) => {
608
+ if (!onHover)
609
+ return;
610
+ onHover(value);
615
611
  };
616
- return { formatData, computeMetric };
617
- };
618
-
619
- var GPaginationDirection;
620
- (function (GPaginationDirection) {
621
- GPaginationDirection["NEXT"] = "NEXT";
622
- GPaginationDirection["PREV"] = "PREV";
623
- })(GPaginationDirection || (GPaginationDirection = {}));
624
-
625
- const TARGET_VISITOR = [
626
- { value: EVisitorType.NEW, label: 'New' },
627
- { value: EVisitorType.RETURNING, label: 'Returning' },
628
- ];
629
- const TARGET_DEVICES = [
630
- { value: EDeviceType.DESKTOP, label: 'Desktop' },
631
- { value: EDeviceType.TABLET, label: 'Tablet' },
632
- { value: EDeviceType.MOBILE, label: 'Mobile' },
633
- ];
634
- const TARGET_CHANNEL = [
635
- { value: ETrafficSourceType.DIRECT, label: 'Direct' },
636
- { value: ETrafficSourceType.EMAIL, label: 'Email' },
637
- { value: ETrafficSourceType.REFERRAL, label: 'Referral' },
638
- { value: ETrafficSourceType.ORGANIC_SOCIAL, label: 'Organic social' },
639
- { value: ETrafficSourceType.ORGANIC_SEARCH, label: 'Organic search' },
640
- { value: ETrafficSourceType.PAID_SOCIAL, label: 'Paid social' },
641
- { value: ETrafficSourceType.PAID_SEARCH, label: 'Paid search' },
642
- { value: ETrafficSourceType.SMS, label: 'SMS' },
643
- ];
644
-
645
- const CAMPAIGN_BACKGROUND_MAIN = {
646
- ORIGIN: '#2C7DFF',
647
- VARIANT: '#F34A70',
648
- };
649
-
650
- const DEFAULT_CURRENT_PERIOD_LABEL = 'Current';
651
- const DEFAULT_PREVIOUS_PERIOD_LABEL = 'Previous';
652
- const CHART_MIN_HEIGHT = 228;
653
- const SERIES_COLORS = {
654
- current: 'rgba(64, 176, 230, 1)',
655
- comparison: 'rgba(161, 202, 231, 1)',
656
- all: ['#2C7DFF', '#F34A70'],
612
+ useEffect(() => {
613
+ setSettingOptions(() => {
614
+ if (selected) {
615
+ return options.filter((item) => selected.includes(item.value)).map((item) => item.value);
616
+ }
617
+ return [];
618
+ });
619
+ // eslint-disable-next-line react-hooks/exhaustive-deps
620
+ }, [selected]);
621
+ return (jsx(BlockStack, { children: options.map((item) => {
622
+ const hasForceUnchecked = dependentDisabledValues?.has(item.value);
623
+ const isOnlyOneSelected = emptySelected && options.filter((opt) => opt.selected).length === 1 && emptySelected;
624
+ const handleCheckboxClick = () => {
625
+ if (isOnlyOneSelected)
626
+ return;
627
+ handleChange(item.value);
628
+ };
629
+ return (jsx("div", { className: cls('flex w-full items-center justify-between', {
630
+ 'cursor-not-allowed': isOnlyOneSelected,
631
+ 'cursor-pointer': !isOnlyOneSelected,
632
+ 'bg-surface-hover rounded-lg': itemHovered === item.value,
633
+ }), onClick: () => {
634
+ if (isOnlyOneSelected || item.disabled)
635
+ return;
636
+ handleCheckboxClick();
637
+ }, onMouseEnter: () => handleHover(item.value), onMouseLeave: () => handleHover(undefined), children: isOnlyOneSelected ? (jsx(GTooltip, { isEnabled: item.tooltip?.isEnabled, ...item.tooltip, children: jsx(Box, { paddingBlock: "150", paddingInline: "200", width: "100%", children: jsxs(InlineStack, { blockAlign: "center", gap: "150", children: [jsx(Checkbox, { label: item.label, labelHidden: true, checked: item.selected, disabled: true }), jsx(Text, { as: "p", variant: "bodyMd", tone: "subdued", children: item.label })] }) }) })) : (jsx(Box, { paddingBlock: "150", paddingInline: "200", minWidth: "0", children: jsxs(InlineStack, { blockAlign: "center", gap: "150", wrap: false, children: [jsx(Checkbox, { label: item.label, labelHidden: true, checked: hasForceUnchecked ? false : settingOptions.includes(item.value), onChange: handleCheckboxClick, disabled: item.disabled }), jsxs(Box, { minWidth: "0", children: [jsx(Text, { as: "p", variant: "bodyMd", truncate: true, tone: hasForceUnchecked ? 'disabled' : 'inherit', children: item.label }), item.description && (jsx(Text, { as: "p", variant: "bodySm", tone: "disabled", truncate: true, children: item.description }))] })] }) })) }, item.value));
638
+ }) }));
657
639
  };
658
- const TREND_TONE = {
659
- POSITIVE: '#007F5F',
660
- NEUTRAL: '#4A4A4A',
640
+ const GCheckboxSingle = ({ options, onChange }) => {
641
+ return (jsx(BlockStack, { gap: "300", children: options.map((item) => (jsx(RadioButton, { label: item.label, checked: item.selected, onChange: () => onChange(item.value), helpText: item.helpText ? jsx(ChoiceHelpText, { item: item }) : undefined }, item.value))) }));
661
642
  };
662
- const PLACEHOLDER_VALUE = '-';
663
643
 
664
- const DEFAULT_CURRENCY_ANALYTIC = 'USD';
665
-
666
- var THUMB_PRODUCT_DEFAULT = "data:image/svg+xml;base64,PHN2ZwogIHdpZHRoPSI5MCIKICBoZWlnaHQ9IjcyIgogIHZpZXdCb3g9IjAgMCA5MCA3MiIKICBmaWxsPSJub25lIgogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKPgogIDxwYXRoCiAgICBkPSJNNDguNzUgMzQuNUM0OS45OTI2IDM0LjUgNTEgMzMuNDkyNiA1MSAzMi4yNUM1MSAzMS4wMDc0IDQ5Ljk5MjYgMzAgNDguNzUgMzBDNDcuNTA3NCAzMCA0Ni41IDMxLjAwNzQgNDYuNSAzMi4yNUM0Ni41IDMzLjQ5MjYgNDcuNTA3NCAzNC41IDQ4Ljc1IDM0LjVaIgogICAgZmlsbD0iIzYxNjE2MSIKICAvPgogIDxwYXRoCiAgICBmaWxsUnVsZT0iZXZlbm9kZCIKICAgIGNsaXBSdWxlPSJldmVub2RkIgogICAgZD0iTTQzLjUyNjggMjYuMjVINDYuNDczMkM0Ny42OTI0IDI2LjI1IDQ4LjY3NTggMjYuMjUgNDkuNDcyMiAyNi4zMTVDNTAuMjkyMiAyNi4zODIgNTEuMDEyNCAyNi41MjM2IDUxLjY3ODcgMjYuODYzMUM1Mi43MzcxIDI3LjQwMjQgNTMuNTk3NiAyOC4yNjI5IDU0LjEzNjkgMjkuMzIxM0M1NC40NzY0IDI5Ljk4NzYgNTQuNjE4IDMwLjcwNzggNTQuNjg1IDMxLjUyNzhDNTQuNzUgMzIuMzI0MiA1NC43NSAzMy4zMDc2IDU0Ljc1IDM0LjUyNjhWMzcuNDczMkM1NC43NSAzOC42OTI0IDU0Ljc1IDM5LjY3NTggNTQuNjg1IDQwLjQ3MjJDNTQuNjE4IDQxLjI5MjIgNTQuNDc2NCA0Mi4wMTI0IDU0LjEzNjkgNDIuNjc4N0M1My41OTc2IDQzLjczNzEgNTIuNzM3MSA0NC41OTc2IDUxLjY3ODcgNDUuMTM2OUM1MS4wMTI0IDQ1LjQ3NjQgNTAuMjkyMiA0NS42MTggNDkuNDcyMiA0NS42ODVDNDguNjc1OCA0NS43NSA0Ny42OTI0IDQ1Ljc1IDQ2LjQ3MzIgNDUuNzVINDMuNTI2OEM0Mi4zMDc2IDQ1Ljc1IDQxLjMyNDIgNDUuNzUgNDAuNTI3OCA0NS42ODVDMzkuNzA3OCA0NS42MTggMzguOTg3NiA0NS40NzY0IDM4LjMyMTMgNDUuMTM2OUMzNy4yNjI5IDQ0LjU5NzYgMzYuNDAyNCA0My43MzcxIDM1Ljg2MzEgNDIuNjc4N0MzNS41MjM2IDQyLjAxMjQgMzUuMzgyIDQxLjI5MjIgMzUuMzE1IDQwLjQ3MjJDMzUuMjUgMzkuNjc1OCAzNS4yNSAzOC42OTI0IDM1LjI1IDM3LjQ3MzJWMzQuNTI2OEMzNS4yNSAzMy4zMDc2IDM1LjI1IDMyLjMyNDIgMzUuMzE1IDMxLjUyNzhDMzUuMzgyIDMwLjcwNzggMzUuNTIzNiAyOS45ODc2IDM1Ljg2MzEgMjkuMzIxM0MzNi40MDI0IDI4LjI2MjkgMzcuMjYyOSAyNy40MDI0IDM4LjMyMTMgMjYuODYzMUMzOC45ODc2IDI2LjUyMzYgMzkuNzA3OCAyNi4zODIgNDAuNTI3OCAyNi4zMTVDNDEuMzI0MiAyNi4yNSA0Mi4zMDc2IDI2LjI1IDQzLjUyNjggMjYuMjVaTTQwLjcxMSAyOC41NTc2QzQwLjAzMDIgMjguNjEzMiAzOS42MzkxIDI4LjcxNjkgMzkuMzQyOCAyOC44Njc5QzM4LjcwNzcgMjkuMTkxNCAzOC4xOTE0IDI5LjcwNzcgMzcuODY3OSAzMC4zNDI4QzM3LjcxNjkgMzAuNjM5MSAzNy42MTMyIDMxLjAzMDIgMzcuNTU3NiAzMS43MTFDMzcuNTAwOSAzMi40MDUgMzcuNSAzMy4yOTYzIDM3LjUgMzQuNTc1VjM2LjcxNzdMMzguNTg0MiAzNS40MTY3QzM5LjU3MjQgMzQuMjMwOSA0MS4zNjU1IDM0LjE0OTYgNDIuNDU2OSAzNS4yNDFMNDYuNSAzOS4yODQxTDQ4LjI2OTQgMzcuNTE0NkM0OS4zNzU3IDM2LjQwODMgNTEuMTk4IDM2LjUwOTMgNTIuMTc1NCAzNy43MzA5TDUyLjQ5OTUgMzguMTM2MUM1Mi41IDM3LjkxMzEgNTIuNSAzNy42NzY1IDUyLjUgMzcuNDI1VjM0LjU3NUM1Mi41IDMzLjI5NjMgNTIuNDk5MSAzMi40MDUgNTIuNDQyNCAzMS43MTFDNTIuMzg2OCAzMS4wMzAyIDUyLjI4MzEgMzAuNjM5MSA1Mi4xMzIxIDMwLjM0MjhDNTEuODA4NiAyOS43MDc3IDUxLjI5MjMgMjkuMTkxNCA1MC42NTcyIDI4Ljg2NzlDNTAuMzYwOSAyOC43MTY5IDQ5Ljk2OTggMjguNjEzMiA0OS4yODkgMjguNTU3NkM0OC41OTUgMjguNTAwOSA0Ny43MDM3IDI4LjUgNDYuNDI1IDI4LjVINDMuNTc1QzQyLjI5NjMgMjguNSA0MS40MDUgMjguNTAwOSA0MC43MTEgMjguNTU3NlpNMzcuNTU3NiA0MC4yODlDMzcuNTU0MyA0MC4yNDkyIDM3LjU1MTMgNDAuMjA4OCAzNy41NDg0IDQwLjE2NzhDMzcuNTcxMSA0MC4xNDQ4IDM3LjU5MzEgNDAuMTIwNiAzNy42MTQyIDQwLjA5NTNMNDAuMzEyNyAzNi44NTcxQzQwLjQ1MzkgMzYuNjg3NyA0MC43MSAzNi42NzYxIDQwLjg2NTkgMzYuODMyTDQ1LjcwNDUgNDEuNjcwNkM0Ni4xNDM4IDQyLjEwOTkgNDYuODU2MSA0Mi4xMDk5IDQ3LjI5NTUgNDEuNjcwNkw0OS44NjA0IDM5LjEwNTZDNTAuMDE4NSAzOC45NDc2IDUwLjI3ODggMzguOTYyIDUwLjQxODQgMzkuMTM2NUw1Mi4yMzc3IDQxLjQxMDdDNTIuMjA1NiA0MS41MDEgNTIuMTcwNCA0MS41ODIyIDUyLjEzMjEgNDEuNjU3MkM1MS44MDg2IDQyLjI5MjMgNTEuMjkyMyA0Mi44MDg2IDUwLjY1NzIgNDMuMTMyMUM1MC4zNjA5IDQzLjI4MzEgNDkuOTY5OCA0My4zODY4IDQ5LjI4OSA0My40NDI0QzQ4LjU5NSA0My40OTkxIDQ3LjcwMzcgNDMuNSA0Ni40MjUgNDMuNUg0My41NzVDNDIuMjk2MyA0My41IDQxLjQwNSA0My40OTkxIDQwLjcxMSA0My40NDI0QzQwLjAzMDIgNDMuMzg2OCAzOS42MzkxIDQzLjI4MzEgMzkuMzQyOCA0My4xMzIxQzM4LjcwNzcgNDIuODA4NiAzOC4xOTE0IDQyLjI5MjMgMzcuODY3OSA0MS42NTcyQzM3LjcxNjkgNDEuMzYwOSAzNy42MTMyIDQwLjk2OTggMzcuNTU3NiA0MC4yODlaIgogICAgZmlsbD0iIzYxNjE2MSIKICAvPgo8L3N2Zz4K";
667
-
668
- var SvgArrowRightIcon = function SvgArrowRightIcon(props) {
669
- return /*#__PURE__*/React.createElement("svg", Object.assign({
670
- viewBox: "0 0 20 20"
671
- }, props), /*#__PURE__*/React.createElement("path", {
672
- fillRule: "evenodd",
673
- d: "M3.5 10a.75.75 0 0 1 .75-.75h9.69l-2.72-2.72a.75.75 0 1 1 1.06-1.06l4 4a.75.75 0 0 1 0 1.06l-4 4a.75.75 0 0 1-1.06-1.06l2.72-2.72h-9.69a.75.75 0 0 1-.75-.75Z"
674
- }));
675
- };
676
- SvgArrowRightIcon.displayName = "ArrowRightIcon";
644
+ const GDiv = forwardRef(({ children, onClick, ...props }, ref) => {
645
+ const onKeyDown = useCallback((e) => {
646
+ if (e.key === 'Enter' || e.key === ' ') {
647
+ e.preventDefault();
648
+ onClick?.();
649
+ }
650
+ }, [onClick]);
651
+ return (jsx("div", { ref: ref, ...props, role: "button", tabIndex: 0, onKeyDown: onKeyDown, onClick: onClick, children: children }));
652
+ });
653
+ GDiv.displayName = 'GDiv';
677
654
 
678
- var SvgCalendarIcon = function SvgCalendarIcon(props) {
679
- return /*#__PURE__*/React.createElement("svg", Object.assign({
680
- viewBox: "0 0 20 20"
681
- }, props), /*#__PURE__*/React.createElement("path", {
682
- fillRule: "evenodd",
683
- d: "M7.75 3.5a.75.75 0 0 0-1.5 0v.407a3.075 3.075 0 0 0-.702.252 3.75 3.75 0 0 0-1.64 1.639c-.226.444-.32.924-.365 1.47-.043.531-.043 1.187-.043 2v1.464c0 .813 0 1.469.043 2 .045.546.14 1.026.366 1.47a3.75 3.75 0 0 0 1.639 1.64c.444.226.924.32 1.47.365.531.043 1.187.043 2 .043h3.383c.323 0 .542 0 .735-.02a3.75 3.75 0 0 0 3.344-3.344c.02-.193.02-.412.02-.735v-2.883c0-.813 0-1.469-.043-2-.045-.546-.14-1.026-.366-1.47a3.75 3.75 0 0 0-1.639-1.64 3.076 3.076 0 0 0-.702-.251v-.407a.75.75 0 0 0-1.5 0v.259c-.373-.009-.794-.009-1.268-.009h-1.964c-.474 0-.895 0-1.268.009v-.259Zm-1.521 1.995c.197-.1.458-.17.912-.207.462-.037 1.057-.038 1.909-.038h1.9c.853 0 1.447 0 1.91.038.453.037.714.107.912.207.423.216.767.56.983.984.1.197.17.458.207.912.014.18.024.38.029.609h-9.982c.006-.228.015-.429.03-.61.036-.453.106-.714.206-.911a2.25 2.25 0 0 1 .984-.984Zm-1.229 4.005v1.2c0 .853 0 1.447.038 1.91.037.453.107.714.207.912.216.423.56.767.984.983.197.1.458.17.912.207.462.037 1.057.038 1.909.038h3.306c.385 0 .52-.001.626-.012a2.25 2.25 0 0 0 2.006-2.006c.011-.106.012-.241.012-.626v-2.606h-10Z"
684
- }));
655
+ const TRANSFORMER_REGEX = /\[(\d+)\](.*?)\[\]/g;
656
+ const GI18NText = (props) => {
657
+ const { children, transformers } = props;
658
+ if (!transformers || Object.values(transformers).length === 0) {
659
+ return jsx(Text, { ...props, children: children });
660
+ }
661
+ const transformContent = (text) => {
662
+ const parts = [];
663
+ let lastIndex = 0;
664
+ text.replace(TRANSFORMER_REGEX, (match, number, childrenContent, offset) => {
665
+ parts.push(text.slice(lastIndex, offset));
666
+ const transformerFunction = transformers[number];
667
+ if (typeof transformerFunction === 'function') {
668
+ parts.push(transformerFunction(childrenContent));
669
+ }
670
+ else {
671
+ parts.push(match);
672
+ }
673
+ lastIndex = offset + match.length;
674
+ return match;
675
+ });
676
+ parts.push(text.slice(lastIndex));
677
+ return parts.map((part, index) => jsx(Fragment$1, { children: part }, index));
678
+ };
679
+ return jsx(Text, { ...props, children: typeof children === 'string' ? transformContent(children) : children });
685
680
  };
686
- SvgCalendarIcon.displayName = "CalendarIcon";
687
681
 
688
- var SvgCheckIcon = function SvgCheckIcon(props) {
689
- return /*#__PURE__*/React.createElement("svg", Object.assign({
690
- viewBox: "0 0 20 20"
691
- }, props), /*#__PURE__*/React.createElement("path", {
692
- fillRule: "evenodd",
693
- d: "M15.78 5.97a.75.75 0 0 1 0 1.06l-6.5 6.5a.75.75 0 0 1-1.06 0l-3.25-3.25a.75.75 0 1 1 1.06-1.06l2.72 2.72 5.97-5.97a.75.75 0 0 1 1.06 0Z"
694
- }));
695
- };
696
- SvgCheckIcon.displayName = "CheckIcon";
682
+ function GOptionList({ options, selected, onChange }) {
683
+ const handleSelect = (value) => {
684
+ onChange([value]);
685
+ };
686
+ const handleKeyDown = (event, value) => {
687
+ if (event.key === 'Enter' || event.key === ' ') {
688
+ event.preventDefault();
689
+ handleSelect(value);
690
+ }
691
+ };
692
+ return (jsx(Box, { padding: "150", children: jsx(BlockStack, { gap: "100", children: options.map((option) => {
693
+ const isSelected = selected.includes(option.value);
694
+ return (jsx("div", { role: "option", "aria-selected": isSelected, tabIndex: 0, onClick: () => handleSelect(option.value), onKeyDown: (e) => handleKeyDown(e, option.value), className: cls('p-1.5 pl-4 rounded-lg cursor-pointer', {
695
+ 'bg-[#F1F1F1]': isSelected,
696
+ 'hover:bg-[#F1F1F1]': !isSelected,
697
+ }), children: jsxs(InlineStack, { align: "space-between", blockAlign: "center", wrap: false, gap: "200", children: [jsx(Box, { minWidth: "0", children: option.label }), isSelected && (jsx(Box, { children: jsx(Icon, { source: SvgCheckIcon }) }))] }) }, option.value));
698
+ }) }) }));
699
+ }
697
700
 
698
- var SvgChevronDownIcon = function SvgChevronDownIcon(props) {
699
- return /*#__PURE__*/React.createElement("svg", Object.assign({
700
- viewBox: "0 0 20 20"
701
- }, props), /*#__PURE__*/React.createElement("path", {
702
- fillRule: "evenodd",
703
- d: "M5.72 8.47a.75.75 0 0 1 1.06 0l3.47 3.47 3.47-3.47a.75.75 0 1 1 1.06 1.06l-4 4a.75.75 0 0 1-1.06 0l-4-4a.75.75 0 0 1 0-1.06Z"
704
- }));
701
+ const GSelector = (props) => {
702
+ const [popoverActive, setPopoverActive] = useState(false);
703
+ const { activatorText, selected, options, emptyLabel, preferredAlignment = 'right', formatActivatorContent = (text) => text.join(', '), } = props;
704
+ const togglePopoverActive = useCallback(() => setPopoverActive((prev) => !prev), []);
705
+ const selectedOption = useMemo(() => {
706
+ return options
707
+ .filter((item) => item.active || item.id === selected)
708
+ .map((item) => item.content || '')
709
+ .filter((item) => !!item);
710
+ }, [options, selected]);
711
+ const activatorContent = useMemo(() => {
712
+ if (selectedOption.length) {
713
+ const selected = formatActivatorContent(selectedOption);
714
+ return activatorText ? `${activatorText}: ${selected}` : selected;
715
+ }
716
+ if (emptyLabel) {
717
+ return activatorText ? `${activatorText}: ${emptyLabel}` : emptyLabel;
718
+ }
719
+ return activatorText;
720
+ }, [selectedOption, emptyLabel, activatorText, formatActivatorContent]);
721
+ const selectorMarkup = useMemo(() => {
722
+ switch (props.variant) {
723
+ case 'choice':
724
+ return jsx(GSelectorChoice, { ...props, setPopoverActive: togglePopoverActive });
725
+ case 'action-list':
726
+ return jsx(GSelectorActionList, { ...props, setPopoverActive: togglePopoverActive });
727
+ }
728
+ }, [props, togglePopoverActive]);
729
+ return (jsx(Popover, { active: popoverActive, activator: jsx("div", { className: "flex items-center gap-1", children: jsx(Button, { onClick: togglePopoverActive, disclosure: popoverActive ? 'up' : 'down', children: activatorContent }) }), autofocusTarget: "first-node", fluidContent: true, onClose: togglePopoverActive, preferredAlignment: preferredAlignment, children: selectorMarkup }));
730
+ };
731
+ const GSelectorChoice = ({ options, selected, onSelect, maxWidth, minWidth, clearable, setPopoverActive, }) => {
732
+ const { t } = useTranslation();
733
+ const items = useMemo(() => {
734
+ if (!options?.length)
735
+ return [];
736
+ return options.map((option) => ({
737
+ value: option.id,
738
+ label: option.content || '',
739
+ selected: false,
740
+ }));
741
+ }, [options]);
742
+ const handleSelection = useCallback((value) => {
743
+ onSelect(value);
744
+ }, [onSelect]);
745
+ return (jsx(Box, { maxWidth: maxWidth, minWidth: minWidth, paddingBlock: "150", children: jsxs(BlockStack, { children: [jsx(BlockStack, { gap: "0", children: jsx(GCheckbox, { multiple: true, options: items, selected: selected, onChange: handleSelection }) }), clearable && (jsx(Box, { paddingBlock: "150", paddingInline: "200", children: jsx(InlineStack, { blockAlign: "center", align: "start", children: jsx(Button, { disabled: !selected?.length, onClick: () => {
746
+ handleSelection([]);
747
+ setPopoverActive(false);
748
+ }, variant: "plain", children: t('Clear') }) }) }))] }) }));
749
+ };
750
+ const GSelectorActionList = ({ options, selected, onSelect, helpText, maxWidth, minWidth, setPopoverActive, }) => {
751
+ const handleSelection = useCallback((value) => {
752
+ onSelect(value);
753
+ setPopoverActive(false);
754
+ }, [onSelect, setPopoverActive]);
755
+ const items = useMemo(() => {
756
+ if (!options?.length)
757
+ return [];
758
+ return options.map((option) => ({
759
+ id: option.id,
760
+ content: option.content,
761
+ helpText: option.helpText,
762
+ onAction: () => handleSelection(option.id),
763
+ active: option.active || option.id === selected,
764
+ suffix: (option.active || option.id === selected) && jsx(Icon, { source: SvgCheckIcon, tone: "success" }),
765
+ }));
766
+ }, [options, selected, handleSelection]);
767
+ return (jsx(Box, { maxWidth: maxWidth, minWidth: minWidth, children: jsxs(BlockStack, { gap: "0", children: [jsx(ActionList, { actionRole: "menuitem", items: items }), helpText] }) }));
705
768
  };
706
- SvgChevronDownIcon.displayName = "ChevronDownIcon";
707
769
 
708
- var SvgChevronRightIcon = function SvgChevronRightIcon(props) {
709
- return /*#__PURE__*/React.createElement("svg", Object.assign({
710
- viewBox: "0 0 20 20"
711
- }, props), /*#__PURE__*/React.createElement("path", {
712
- fillRule: "evenodd",
713
- d: "M7.72 14.53a.75.75 0 0 1 0-1.06l3.47-3.47-3.47-3.47a.75.75 0 0 1 1.06-1.06l4 4a.75.75 0 0 1 0 1.06l-4 4a.75.75 0 0 1-1.06 0Z"
714
- }));
770
+ const GTextLink = ({ linkAction, isDisabled, disabledFocus, children }) => {
771
+ if (!linkAction || isDisabled) {
772
+ return jsx(Fragment, { children: children });
773
+ }
774
+ return (jsx("span", { className: cls('GTextLink', { 'GTextLink--disabled-focus': disabledFocus }), children: jsx(Link, { ...linkAction, children: jsx(Fragment, { children: children }) }) }));
715
775
  };
716
- SvgChevronRightIcon.displayName = "ChevronRightIcon";
717
776
 
718
- var SvgChevronUpIcon = function SvgChevronUpIcon(props) {
719
- return /*#__PURE__*/React.createElement("svg", Object.assign({
720
- viewBox: "0 0 20 20"
721
- }, props), /*#__PURE__*/React.createElement("path", {
722
- fillRule: "evenodd",
723
- d: "M14.53 12.28a.75.75 0 0 1-1.06 0l-3.47-3.47-3.47 3.47a.75.75 0 0 1-1.06-1.06l4-4a.75.75 0 0 1 1.06 0l4 4a.75.75 0 0 1 0 1.06Z"
724
- }));
777
+ const GSkeletonDisplayText = (props) => {
778
+ const height = props.height ?? '50px';
779
+ return (jsxs("div", { className: "Polaris-GSkeletonDisplayText", children: [jsx("style", { children: `.Polaris-GSkeletonDisplayText .Polaris-SkeletonDisplayText__DisplayText { height: ${height} !important; }` }), jsx(SkeletonDisplayText, { maxWidth: "100%", size: "extraLarge" })] }));
725
780
  };
726
- SvgChevronUpIcon.displayName = "ChevronUpIcon";
727
781
 
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(' ');
782
+ /**
783
+ * Helper function to generate a variation class name.
784
+ * @param name - Base name of the class.
785
+ * @param value - Variation value to append.
786
+ * @returns Combined class name.
787
+ */
788
+ function variationName(name, value) {
789
+ return `${name}${value.charAt(0).toUpperCase()}${value.slice(1)}`;
743
790
  }
791
+ const GThumbnail = ({ source, alt, size, grayscale, defaultSource = THUMB_PRODUCT_DEFAULT, width = '80', height = '80', classRemoved = false, }) => {
792
+ const sizeClass = size && variationName('Polaris-Thumbnail--size', size);
793
+ const filterClass = grayscale && 'Polaris-GThumbnail--filter';
794
+ const className = cls('Polaris-Thumbnail', sizeClass);
795
+ const thumbnail = (jsx("img", { onError: (e) => {
796
+ e.currentTarget.src = defaultSource;
797
+ }, alt: alt ?? 'Thumbnail', src: `${source ?? defaultSource}`, width: width, height: height, style: {
798
+ '--gp-grayscale-percentage': grayscale || '100%',
799
+ }, className: cls('Polaris-GThumbnail', filterClass) }));
800
+ if (classRemoved)
801
+ return thumbnail;
802
+ return jsx("span", { className: className, children: thumbnail });
803
+ };
744
804
 
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);
805
+ const SIZE_CLASS = {
806
+ default: 'w-[210px]',
807
+ wide: 'w-[320px]',
808
+ large: 'w-[328px]',
809
+ };
810
+ const ALIGNMENT_MAP = {
811
+ start: 'flex justify-start',
812
+ center: 'flex justify-center',
813
+ end: 'flex justify-end',
814
+ };
815
+ const GTooltipCard = forwardRef((props, ref) => {
816
+ const { tooltip, wrapper = 'div', activatorProps, isHideBorder, alignment, delay = 500, textDecoration = 'none', popoverRef, preferredAlignment = 'left', showArrow = false, } = props;
817
+ const { width = 'default' } = tooltip ?? {};
818
+ const [isMouseEnter, setIsMouseEnter] = useState(false);
819
+ const TooltipCardWrapper = wrapper;
820
+ const sizeClass = SIZE_CLASS[width];
821
+ const timeoutRef = useRef(null);
822
+ const handleMouseEnter = () => {
823
+ timeoutRef.current = setTimeout(() => {
824
+ setIsMouseEnter(true);
825
+ }, delay);
826
+ };
827
+ const handleMouseLeave = () => {
828
+ if (timeoutRef.current) {
829
+ clearTimeout(timeoutRef.current);
830
+ timeoutRef.current = null;
794
831
  }
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
- }
832
+ setIsMouseEnter(false);
833
+ };
834
+ useImperativeHandle(ref, () => ({ onClose: handleMouseLeave }));
835
+ return (jsx(TooltipCardWrapper, { className: cls('GTooltipCard cursor-pointer', alignment && ALIGNMENT_MAP[alignment], {
836
+ 'GTooltipCard--text-underline': textDecoration === 'underline',
837
+ }), onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: jsx(Popover, { ref: popoverRef, activator: !isHideBorder ? (jsx(Box, { borderBlockEndWidth: "025", borderStyle: "dashed", borderColor: "border-tertiary", as: wrapper, ...activatorProps, children: props.children })) : (jsx(InlineStack, { children: props.children })), activatorWrapper: wrapper, onClose: () => { }, active: isMouseEnter, preferredPosition: "below", preferredAlignment: preferredAlignment, children: tooltip && (jsx("div", { className: cls(sizeClass, { 'GTooltipCard-arrow': showArrow }), children: jsx(Box, { padding: "400", children: jsxs(BlockStack, { gap: "200", children: [jsxs(BlockStack, { gap: "100", children: [jsx(Text, { as: "span", variant: "headingSm", fontWeight: "semibold", children: tooltip.title }), jsxs(BlockStack, { gap: "200", children: [jsx(Text, { as: "span", variant: "bodyMd", tone: "subdued", fontWeight: "medium", children: jsx("span", { dangerouslySetInnerHTML: { __html: tooltip.content } }) }), tooltip.contentList && (jsx(List, { type: "bullet", children: tooltip.contentList.map((item) => (jsx(List.Item, { children: jsx(Text, { as: "span", variant: "bodyMd", tone: "subdued", fontWeight: "medium", children: item }) }, item))) }))] })] }), tooltip.formula && (jsx("div", { className: "rounded-md font-mono", style: { fontSize: '12px' }, children: tooltip.formula }))] }) }) })) }) }));
838
+ });
839
+ GTooltipCard.displayName = 'GTooltipCard';
808
840
 
809
- const GClickable = ({ children, fullWidth = false, cursor = 'pointer', onClick, onMouseEnter, onMouseLeave, }) => {
810
- return (jsx("div", { role: "button", tabIndex: 0, className: cls({
811
- 'w-full': fullWidth,
812
- 'cursor-pointer': cursor === 'pointer',
813
- 'cursor-default': cursor === 'default',
814
- 'cursor-not-allowed': cursor === 'not-allowed',
815
- }), onKeyDown: (e) => {
816
- if (e.key === 'Enter' || e.key === ' ') {
817
- e.preventDefault();
818
- onClick();
819
- }
820
- }, onClick: onClick, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, children: children }));
821
- };
822
-
823
- const GActivatorPopover = ({ onClick, active, content, textProps, boxProps: customBoxProps, disabled, icon: customIcon, }) => {
824
- const boxProps = useMemo(() => {
825
- if (disabled) {
826
- return {
827
- borderColor: 'border-disabled',
828
- background: 'bg-surface-disabled',
829
- ...customBoxProps,
830
- };
831
- }
832
- return {
833
- shadow: active ? 'button-inset' : 'button',
834
- background: active ? 'bg-fill-active' : 'bg-fill',
835
- ...customBoxProps,
836
- };
837
- }, [active, disabled, customBoxProps]);
838
- const toneClass = useMemo(() => {
839
- if (disabled) {
840
- return 'text-[var(--p-color-text-disabled)]';
841
+ const GViewBySelector = ({ activatorText, selected, options, minWidth, maxWidth, preferredAlignment = 'right', onSelect, }) => {
842
+ const [popoverActive, setPopoverActive] = useState(false);
843
+ const [itemHover, setItemHover] = useState(null);
844
+ const togglePopoverActive = () => setPopoverActive((prev) => !prev);
845
+ const selectedOption = useMemo(() => {
846
+ return options.find((item) => item.id === selected);
847
+ }, [options, selected]);
848
+ const activatorContent = useMemo(() => {
849
+ if (selectedOption) {
850
+ const content = selectedOption.title ?? selectedOption.content;
851
+ return activatorText ? `${activatorText}: ${content}` : content;
841
852
  }
842
- return active ? 'text-[var(--p-color-text-subdued)]' : 'text-[var(--p-color-text)]';
843
- }, [active, disabled]);
844
- const textComponent = useMemo(() => {
845
- return (jsx(Text, { as: "span", variant: "bodyMd", fontWeight: "medium", tone: disabled ? 'inherit' : textProps?.tone, truncate: true, ...(textProps?.variant && { variant: textProps.variant }), children: content }));
846
- }, [content, textProps, disabled]);
847
- const handleClick = useCallback(() => {
848
- if (disabled)
849
- return;
850
- onClick();
851
- }, [disabled, onClick]);
852
- return (jsx(GClickable, { cursor: disabled ? 'default' : 'pointer', onClick: handleClick, children: jsx("div", { className: cls(toneClass), children: jsxs(Box, { padding: "150", paddingInline: "300", paddingInlineEnd: "150", borderRadius: "200", ...boxProps, children: [customIcon && (jsxs(InlineStack, { gap: "200", align: "center", wrap: false, children: [jsx(Box, { children: jsx(Icon, { source: customIcon }) }), textComponent] })), !customIcon && (jsxs(InlineGrid, { columns: "1fr 20px", gap: "200", alignItems: "center", children: [textComponent, jsx(Icon, { source: active ? SvgChevronUpIcon : SvgChevronDownIcon })] }))] }) }) }));
853
- };
854
-
855
- const GBlockCenter = ({ height, align, inlineAlign, display, ...props }) => {
856
- const stickyStyle = useMemo(() => {
857
- if (props.position !== 'sticky')
858
- return {};
859
- const style = {
860
- position: 'sticky',
861
- };
862
- if (props.insetInlineStart)
863
- style.insetInlineStart = Number(props.insetInlineStart) * 4;
864
- if (props.insetInlineEnd)
865
- style.insetInlineEnd = Number(props.insetInlineEnd) * 4;
866
- if (props.insetBlockStart)
867
- style.insetBlockStart = Number(props.insetBlockStart) * 4;
868
- if (props.insetBlockEnd)
869
- style.insetBlockEnd = Number(props.insetBlockEnd) * 4;
870
- return style;
871
- }, [props.position, props.insetInlineStart, props.insetInlineEnd, props.insetBlockStart, props.insetBlockEnd]);
872
- return (jsx("div", { className: "Polaris-GBlockCenter", style: {
873
- ...stickyStyle,
874
- '--gp-block-center-height': height,
875
- '--gp-block-center-display': display,
876
- '--gp-block-center-align': align,
877
- '--gp-block-center-inline-align': inlineAlign,
878
- '--gp-block-center-overflow-x': props.overflowX,
879
- '--gp-block-center-overflow-y': props.overflowY,
880
- }, children: jsx(Box, { ...props }) }));
853
+ return activatorText;
854
+ }, [selectedOption, activatorText]);
855
+ const handleSelect = (value) => {
856
+ onSelect(value);
857
+ setPopoverActive(false);
858
+ };
859
+ 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) => {
860
+ const isSelected = option.id === selected;
861
+ const isHover = itemHover === option.id;
862
+ const borderColor = isSelected ? 'input-border' : isHover ? 'border-hover' : 'transparent';
863
+ 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));
864
+ }) }) }) }));
881
865
  };
882
866
 
883
- const GTooltip = ({ isEnabled = true, content, maxWidth, ...props }) => {
884
- const hasContent = isEnabled && !!content;
885
- return hasContent ? (jsx(Tooltip, { width: "wide", hoverDelay: 500, content: content, ...props, accessibilityLabel: maxWidth?.toString() })) : (props.children);
867
+ const ChoiceHelpText = ({ item }) => {
868
+ return (jsxs(Text, { as: "p", variant: "bodyMd", children: [item.description, item.inlineAction && (jsx(Link, { monochrome: true, onClick: () => {
869
+ if (item.inlineAction?.onAction) {
870
+ item.inlineAction?.onAction();
871
+ }
872
+ else {
873
+ window.open(item.inlineAction?.url, item.inlineAction?.target ?? '_blank');
874
+ }
875
+ }, children: item.inlineAction?.content }))] }));
886
876
  };
887
877
 
888
- const GButton = ({ activatorWrapper, children, iconRight, inset, stopPropagation = true, onClick, themeTone = 'light', variant, ...props }) => {
889
- const Wrapper = activatorWrapper || 'div';
890
- const isNeutral = variant === 'neutral';
891
- const polarisVariant = isNeutral ? undefined : variant;
892
- const handleClick = (e) => {
893
- stopPropagation && e.stopPropagation();
894
- if (props.disabled)
895
- return;
896
- onClick?.();
897
- };
898
- const button = (jsx(GTooltip, { activatorWrapper: "tooltip-content", ...props.tooltip, children: jsx(Wrapper, { className: cls('Polaris-GButton', {
899
- 'Polaris-GButton--icon-right': iconRight,
900
- 'Polaris-GButton--dark': themeTone === 'dark',
901
- 'Polaris-GButton--neutral': isNeutral,
902
- 'cursor-default': props.disabled,
903
- 'Polaris-GButton--fullWidth': props.fullWidth,
904
- flex: inset,
905
- }), onClick: handleClick, children: jsx(Button, { variant: polarisVariant, ...props, children: children }) }) }));
906
- if (inset) {
907
- return jsx(Box, { padding: "100", children: button });
908
- }
909
- return button;
878
+ const GChartSkeleton = () => {
879
+ return jsx(GSkeletonDisplayText, { height: "188px" });
910
880
  };
911
881
 
912
- const GCheckbox = ({ ...props }) => {
913
- return props.multiple ? jsx(GCheckboxMultiple, { ...props }) : jsx(GCheckboxSingle, { ...props });
914
- };
915
- const GCheckboxMultiple = ({ options, onChange, onChangeSingleValue, emptySelected, selected, onHover, itemHovered, dependentDisabledValues, }) => {
916
- const [settingOptions, setSettingOptions] = useState([]);
917
- const handleChange = (value) => {
918
- if (onChangeSingleValue) {
919
- onChangeSingleValue(value);
920
- }
921
- const updatedOptions = settingOptions.includes(value)
922
- ? settingOptions.filter((item) => item !== value)
923
- : [...settingOptions, value];
924
- setSettingOptions(updatedOptions);
925
- onChange(updatedOptions);
926
- };
927
- const handleHover = (value) => {
928
- if (!onHover)
929
- return;
930
- onHover(value);
931
- };
932
- useEffect(() => {
933
- setSettingOptions(() => {
934
- if (selected) {
935
- return options.filter((item) => selected.includes(item.value)).map((item) => item.value);
936
- }
937
- return [];
938
- });
939
- // eslint-disable-next-line react-hooks/exhaustive-deps
940
- }, [selected]);
941
- return (jsx(BlockStack, { children: options.map((item) => {
942
- const hasForceUnchecked = dependentDisabledValues?.has(item.value);
943
- const isOnlyOneSelected = emptySelected && options.filter((opt) => opt.selected).length === 1 && emptySelected;
944
- const handleCheckboxClick = () => {
945
- if (isOnlyOneSelected)
946
- return;
947
- handleChange(item.value);
948
- };
949
- return (jsx("div", { className: cls('flex w-full items-center justify-between', {
950
- 'cursor-not-allowed': isOnlyOneSelected,
951
- 'cursor-pointer': !isOnlyOneSelected,
952
- 'bg-surface-hover rounded-lg': itemHovered === item.value,
953
- }), onClick: () => {
954
- if (isOnlyOneSelected || item.disabled)
955
- return;
956
- handleCheckboxClick();
957
- }, onMouseEnter: () => handleHover(item.value), onMouseLeave: () => handleHover(undefined), children: isOnlyOneSelected ? (jsx(GTooltip, { isEnabled: item.tooltip?.isEnabled, ...item.tooltip, children: jsx(Box, { paddingBlock: "150", paddingInline: "200", width: "100%", children: jsxs(InlineStack, { blockAlign: "center", gap: "150", children: [jsx(Checkbox, { label: item.label, labelHidden: true, checked: item.selected, disabled: true }), jsx(Text, { as: "p", variant: "bodyMd", tone: "subdued", children: item.label })] }) }) })) : (jsx(Box, { paddingBlock: "150", paddingInline: "200", minWidth: "0", children: jsxs(InlineStack, { blockAlign: "center", gap: "150", wrap: false, children: [jsx(Checkbox, { label: item.label, labelHidden: true, checked: hasForceUnchecked ? false : settingOptions.includes(item.value), onChange: handleCheckboxClick, disabled: item.disabled }), jsxs(Box, { minWidth: "0", children: [jsx(Text, { as: "p", variant: "bodyMd", truncate: true, tone: hasForceUnchecked ? 'disabled' : 'inherit', children: item.label }), item.description && (jsx(Text, { as: "p", variant: "bodySm", tone: "disabled", truncate: true, children: item.description }))] })] }) })) }, item.value));
958
- }) }));
959
- };
960
- const GCheckboxSingle = ({ options, onChange }) => {
961
- return (jsx(BlockStack, { gap: "300", children: options.map((item) => (jsx(RadioButton, { label: item.label, checked: item.selected, onChange: () => onChange(item.value), helpText: item.helpText ? jsx(ChoiceHelpText, { item: item }) : undefined }, item.value))) }));
882
+ const LINE_SERIES_COLORS = {
883
+ comparison: SERIES_COLORS.comparison,
884
+ single: SERIES_COLORS.current,
885
+ all: [...SERIES_COLORS.all],
962
886
  };
963
-
964
- const GDiv = forwardRef(({ children, onClick, ...props }, ref) => {
965
- const onKeyDown = useCallback((e) => {
966
- if (e.key === 'Enter' || e.key === ' ') {
967
- e.preventDefault();
968
- onClick?.();
969
- }
970
- }, [onClick]);
971
- return (jsx("div", { ref: ref, ...props, role: "button", tabIndex: 0, onKeyDown: onKeyDown, onClick: onClick, children: children }));
972
- });
973
- GDiv.displayName = 'GDiv';
974
-
975
- const TRANSFORMER_REGEX = /\[(\d+)\](.*?)\[\]/g;
976
- const GI18NText = (props) => {
977
- const { children, transformers } = props;
978
- if (!transformers || Object.values(transformers).length === 0) {
979
- return jsx(Text, { ...props, children: children });
980
- }
981
- const transformContent = (text) => {
982
- const parts = [];
983
- let lastIndex = 0;
984
- text.replace(TRANSFORMER_REGEX, (match, number, childrenContent, offset) => {
985
- parts.push(text.slice(lastIndex, offset));
986
- const transformerFunction = transformers[number];
987
- if (typeof transformerFunction === 'function') {
988
- parts.push(transformerFunction(childrenContent));
989
- }
990
- else {
991
- parts.push(match);
992
- }
993
- lastIndex = offset + match.length;
994
- return match;
995
- });
996
- parts.push(text.slice(lastIndex));
997
- return parts.map((part, index) => jsx(Fragment$1, { children: part }, index));
998
- };
999
- return jsx(Text, { ...props, children: typeof children === 'string' ? transformContent(children) : children });
887
+ const MetricChartProvider = ({ children, minHeight = CHART_MIN_HEIGHT, seriesColors = LINE_SERIES_COLORS, }) => {
888
+ return (jsx(PolarisVizProvider, { themes: {
889
+ Light: {
890
+ chartContainer: {
891
+ minHeight,
892
+ },
893
+ grid: {
894
+ horizontalOverflow: true,
895
+ verticalOverflow: true,
896
+ horizontalMargin: 0,
897
+ },
898
+ seriesColors,
899
+ },
900
+ }, children: children }));
1000
901
  };
1001
902
 
1002
- function GOptionList({ options, selected, onChange }) {
1003
- const handleSelect = (value) => {
1004
- onChange([value]);
1005
- };
1006
- const handleKeyDown = (event, value) => {
1007
- if (event.key === 'Enter' || event.key === ' ') {
1008
- event.preventDefault();
1009
- handleSelect(value);
1010
- }
903
+ /**
904
+ * Returns a stateful value, and a set of memoized functions to toggle it,
905
+ * set it to true and set it to false
906
+ */
907
+ function useToggle(initialState) {
908
+ const [value, setState] = useState(initialState);
909
+ return {
910
+ value,
911
+ toggle: useCallback(() => setState((state) => !state), []),
912
+ setTrue: useCallback(() => setState(true), []),
913
+ setFalse: useCallback(() => setState(false), []),
1011
914
  };
1012
- return (jsx(Box, { padding: "150", children: jsx(BlockStack, { gap: "100", children: options.map((option) => {
1013
- const isSelected = selected.includes(option.value);
1014
- return (jsx("div", { role: "option", "aria-selected": isSelected, tabIndex: 0, onClick: () => handleSelect(option.value), onKeyDown: (e) => handleKeyDown(e, option.value), className: cls('p-1.5 pl-4 rounded-lg cursor-pointer', {
1015
- 'bg-[#F1F1F1]': isSelected,
1016
- 'hover:bg-[#F1F1F1]': !isSelected,
1017
- }), children: jsxs(InlineStack, { align: "space-between", blockAlign: "center", wrap: false, gap: "200", children: [jsx(Box, { minWidth: "0", children: option.label }), isSelected && (jsx(Box, { children: jsx(Icon, { source: SvgCheckIcon }) }))] }) }, option.value));
1018
- }) }) }));
1019
915
  }
1020
916
 
1021
- const GSelector = (props) => {
1022
- const [popoverActive, setPopoverActive] = useState(false);
1023
- const { activatorText, selected, options, emptyLabel, preferredAlignment = 'right', formatActivatorContent = (text) => text.join(', '), } = props;
1024
- const togglePopoverActive = useCallback(() => setPopoverActive((prev) => !prev), []);
1025
- const selectedOption = useMemo(() => {
1026
- return options
1027
- .filter((item) => item.active || item.id === selected)
1028
- .map((item) => item.content || '')
1029
- .filter((item) => !!item);
1030
- }, [options, selected]);
1031
- const activatorContent = useMemo(() => {
1032
- if (selectedOption.length) {
1033
- const selected = formatActivatorContent(selectedOption);
1034
- return activatorText ? `${activatorText}: ${selected}` : selected;
917
+ const NONE_VALUE = 'None';
918
+ const PLACEHOLDER_VALUE = '-';
919
+
920
+ const TOTALS_SUFFIX = '___totals';
921
+ const COMPARE_PREFIX = 'comparison___';
922
+ const COMPARE_SUFFIX = '___previous_period';
923
+ const COMPARE_TOTALS_SUFFIX = `${COMPARE_SUFFIX}${TOTALS_SUFFIX}`;
924
+
925
+ const OPERATOR_IS = 'is';
926
+
927
+ var EAnalyticDataType;
928
+ (function (EAnalyticDataType) {
929
+ EAnalyticDataType["DATE"] = "DATE";
930
+ EAnalyticDataType["ARRAY"] = "ARRAY";
931
+ EAnalyticDataType["OBJECT"] = "OBJECT";
932
+ EAnalyticDataType["STRING"] = "STRING";
933
+ EAnalyticDataType["INTEGER"] = "INTEGER";
934
+ EAnalyticDataType["CURRENCY"] = "CURRENCY";
935
+ EAnalyticDataType["PERCENT"] = "PERCENT";
936
+ EAnalyticDataType["DURATION"] = "DURATION";
937
+ EAnalyticDataType["MONTH"] = "MONTH_TIMESTAMP";
938
+ EAnalyticDataType["QUARTER"] = "QUARTER_TIMESTAMP";
939
+ EAnalyticDataType["DAY"] = "DAY_TIMESTAMP";
940
+ EAnalyticDataType["WEEK"] = "WEEK_TIMESTAMP";
941
+ EAnalyticDataType["YEAR"] = "YEAR_TIMESTAMP";
942
+ EAnalyticDataType["HOUR"] = "HOUR_TIMESTAMP";
943
+ })(EAnalyticDataType || (EAnalyticDataType = {}));
944
+ var EAnalyticColumnKey;
945
+ (function (EAnalyticColumnKey) {
946
+ EAnalyticColumnKey["CAMPAIGNS"] = "experiments";
947
+ EAnalyticColumnKey["VISITOR_ITEMS"] = "visitor_items";
948
+ EAnalyticColumnKey["DEVICE_ITEMS"] = "device_items";
949
+ EAnalyticColumnKey["TRAFFIC_SOURCE_ITEMS"] = "traffic_source_items";
950
+ })(EAnalyticColumnKey || (EAnalyticColumnKey = {}));
951
+
952
+ var EAnalyticSource;
953
+ (function (EAnalyticSource) {
954
+ EAnalyticSource["SESSIONS"] = "sessions";
955
+ EAnalyticSource["SALES"] = "sales";
956
+ })(EAnalyticSource || (EAnalyticSource = {}));
957
+
958
+ var EComparisonOperator;
959
+ (function (EComparisonOperator) {
960
+ EComparisonOperator["EQ"] = "=";
961
+ EComparisonOperator["IN"] = "IN";
962
+ EComparisonOperator["LIKE"] = "LIKE";
963
+ })(EComparisonOperator || (EComparisonOperator = {}));
964
+ var EGroupOperator;
965
+ (function (EGroupOperator) {
966
+ EGroupOperator["OR"] = "OR";
967
+ EGroupOperator["AND"] = "AND";
968
+ })(EGroupOperator || (EGroupOperator = {}));
969
+
970
+ var EFilterField;
971
+ (function (EFilterField) {
972
+ EFilterField["DEVICE"] = "device";
973
+ EFilterField["DEVICES"] = "devices";
974
+ EFilterField["VISITOR"] = "visitor_type";
975
+ EFilterField["VISITORS"] = "visitor_types";
976
+ EFilterField["TRAFFIC_SOURCE"] = "traffic_source";
977
+ EFilterField["TRAFFIC_SOURCES"] = "traffic_sources";
978
+ EFilterField["VERSION"] = "version";
979
+ EFilterField["VERSIONS"] = "versions";
980
+ EFilterField["SINGLE_PAGE"] = "page_path";
981
+ EFilterField["LIST_PAGE"] = "page_paths";
982
+ EFilterField["GROUP_CAMPAIGN_ITEM"] = "group_campaign_item";
983
+ EFilterField["GROUP_CAMPAIGN_ITEMS"] = "group_campaign_items";
984
+ EFilterField["SINGLE_CAMPAIGN"] = "experiment_id";
985
+ EFilterField["GROUP_CAMPAIGN"] = "experiment_group_id";
986
+ EFilterField["CAMPAIGN_VERSION_ID"] = "version_id";
987
+ EFilterField["GROUP_CAMPAIGN_VERSION_ID"] = "group_version_id";
988
+ })(EFilterField || (EFilterField = {}));
989
+
990
+ var EOperatorField;
991
+ (function (EOperatorField) {
992
+ EOperatorField["DEVICE_OPERATOR"] = "deviceOperator";
993
+ EOperatorField["VISITOR_OPERATOR"] = "visitorOperator";
994
+ EOperatorField["TRAFFIC_SOURCE_OPERATOR"] = "trafficSourceOperator";
995
+ EOperatorField["VERSION_OPERATOR"] = "versionOperator";
996
+ EOperatorField["PAGE_OPERATOR"] = "pageOperator";
997
+ EOperatorField["CAMPAIGN_ITEM_OPERATOR"] = "campaignItemOperator";
998
+ })(EOperatorField || (EOperatorField = {}));
999
+
1000
+ /**
1001
+ * Controls which totals columns are appended to the query result.
1002
+ *
1003
+ * - NONE → no totals, GROUP BY only.
1004
+ * - TOTALS → adds `<metric>___totals` (grand total only). Use with single-dimension GROUP BY.
1005
+ * - ALL → adds subtotals per dimension group + grand total. Use with multi-dimension GROUP BY.
1006
+ */
1007
+ var EGroupWithClause;
1008
+ (function (EGroupWithClause) {
1009
+ EGroupWithClause["NONE"] = "";
1010
+ EGroupWithClause["TOTALS"] = "TOTALS";
1011
+ EGroupWithClause["ALL"] = "WITH GROUP_TOTALS, TOTALS";
1012
+ })(EGroupWithClause || (EGroupWithClause = {}));
1013
+
1014
+ var EOrderDirectionType;
1015
+ (function (EOrderDirectionType) {
1016
+ EOrderDirectionType["ASC"] = "ASC";
1017
+ EOrderDirectionType["DESC"] = "DESC";
1018
+ })(EOrderDirectionType || (EOrderDirectionType = {}));
1019
+
1020
+ var EPageMetric;
1021
+ (function (EPageMetric) {
1022
+ EPageMetric["PAGE_ITEMS"] = "page_items";
1023
+ EPageMetric["PAGE_PATHS"] = "page_paths";
1024
+ })(EPageMetric || (EPageMetric = {}));
1025
+ var EPageDimension;
1026
+ (function (EPageDimension) {
1027
+ EPageDimension["PAGE_PATH"] = "page_path";
1028
+ })(EPageDimension || (EPageDimension = {}));
1029
+ var EPageField;
1030
+ (function (EPageField) {
1031
+ EPageField["SHOPIFY_PAGE_ID"] = "shopify_page_id";
1032
+ EPageField["LOCATION_PATH"] = "location_path";
1033
+ EPageField["PAGE_TYPE"] = "page_type";
1034
+ EPageField["PAGE_TITLE"] = "page_title";
1035
+ EPageField["PAGE_PATH"] = "page_path";
1036
+ EPageField["TEMPLATE_SUFFIX"] = "template_suffix";
1037
+ })(EPageField || (EPageField = {}));
1038
+
1039
+ var ERowReaderMode;
1040
+ (function (ERowReaderMode) {
1041
+ ERowReaderMode["DEFAULT"] = "DEFAULT";
1042
+ ERowReaderMode["COMPARISON"] = "COMPARISON";
1043
+ ERowReaderMode["TOTALS"] = "TOTALS";
1044
+ ERowReaderMode["COMPARISON_TOTALS"] = "COMPARISON_TOTALS";
1045
+ })(ERowReaderMode || (ERowReaderMode = {}));
1046
+
1047
+ var ETimeDimension;
1048
+ (function (ETimeDimension) {
1049
+ ETimeDimension["HOUR"] = "hour";
1050
+ ETimeDimension["DAY"] = "day";
1051
+ ETimeDimension["WEEK"] = "week";
1052
+ ETimeDimension["MONTH"] = "month";
1053
+ ETimeDimension["QUARTER"] = "quarter";
1054
+ ETimeDimension["YEAR"] = "year";
1055
+ })(ETimeDimension || (ETimeDimension = {}));
1056
+
1057
+ ({
1058
+ [ERowReaderMode.DEFAULT]: { prefix: '', suffix: '' },
1059
+ [ERowReaderMode.COMPARISON]: { prefix: COMPARE_PREFIX, suffix: COMPARE_SUFFIX },
1060
+ [ERowReaderMode.TOTALS]: { prefix: '', suffix: TOTALS_SUFFIX },
1061
+ [ERowReaderMode.COMPARISON_TOTALS]: { prefix: COMPARE_PREFIX, suffix: COMPARE_TOTALS_SUFFIX },
1062
+ });
1063
+
1064
+ const formatAnalyticDate = (dateString) => {
1065
+ if (!dateString)
1066
+ return 'None';
1067
+ const date = dayjsTz(dateString);
1068
+ const now = dayjsTz();
1069
+ const yesterday = dayjsTz().subtract(1, 'day');
1070
+ const isToday = date.format('YYYY-MM-DD') === now.format('YYYY-MM-DD');
1071
+ const isYesterday = date.format('YYYY-MM-DD') === yesterday.format('YYYY-MM-DD');
1072
+ if (isToday) {
1073
+ return `Today at ${date.format('HH:mm')}`;
1074
+ }
1075
+ if (isYesterday) {
1076
+ return `Yesterday at ${date.format('HH:mm')}`;
1077
+ }
1078
+ const daysDiff = now.diff(date, 'day');
1079
+ const isWithinWeek = daysDiff >= 0 && daysDiff < 7;
1080
+ if (isWithinWeek) {
1081
+ return `${date.format('dddd')} at ${date.format('HH:mm')}`;
1082
+ }
1083
+ return `${date.format('MMM D')} at ${date.format('hh:mm a')}`;
1084
+ };
1085
+
1086
+ const formatAnalyticData = ({ value, formatter, getTextPrice, name, }) => {
1087
+ const dataTypeIsObjectOrArray = value !== null && (typeof value === 'object' || Array.isArray(value));
1088
+ if (dataTypeIsObjectOrArray)
1089
+ return value;
1090
+ switch (formatter) {
1091
+ case EAnalyticDataType.INTEGER: {
1092
+ return numberWithCommas((value ?? 0).toString());
1035
1093
  }
1036
- if (emptyLabel) {
1037
- return activatorText ? `${activatorText}: ${emptyLabel}` : emptyLabel;
1094
+ case EAnalyticDataType.CURRENCY: {
1095
+ if (!getTextPrice)
1096
+ return `${value ?? 0}`;
1097
+ return getTextPrice(value, false);
1038
1098
  }
1039
- return activatorText;
1040
- }, [selectedOption, emptyLabel, activatorText, formatActivatorContent]);
1041
- const selectorMarkup = useMemo(() => {
1042
- switch (props.variant) {
1043
- case 'choice':
1044
- return jsx(GSelectorChoice, { ...props, setPopoverActive: togglePopoverActive });
1045
- case 'action-list':
1046
- return jsx(GSelectorActionList, { ...props, setPopoverActive: togglePopoverActive });
1099
+ case EAnalyticDataType.DATE: {
1100
+ return formatAnalyticDate(value);
1047
1101
  }
1048
- }, [props, togglePopoverActive]);
1049
- return (jsx(Popover, { active: popoverActive, activator: jsx("div", { className: "flex items-center gap-1", children: jsx(Button, { onClick: togglePopoverActive, disclosure: popoverActive ? 'up' : 'down', children: activatorContent }) }), autofocusTarget: "first-node", fluidContent: true, onClose: togglePopoverActive, preferredAlignment: preferredAlignment, children: selectorMarkup }));
1102
+ case EAnalyticDataType.PERCENT: {
1103
+ if (typeof value !== 'number')
1104
+ return calcPercentageString(0, 1, 2) ?? '';
1105
+ return calcPercentageString(value / 100, 1, 2) ?? '';
1106
+ }
1107
+ case EAnalyticDataType.DURATION: {
1108
+ return getTimeDurationLabel(Number(value));
1109
+ }
1110
+ case EAnalyticDataType.STRING: {
1111
+ const fallbackValue = name === EAnalyticColumnKey.CAMPAIGNS ? '' : NONE_VALUE;
1112
+ return value ?? fallbackValue;
1113
+ }
1114
+ case EAnalyticDataType.DAY: {
1115
+ return getFormattedByInterval(value, AnalyticInterval.DAY, { isExpandDetail: true });
1116
+ }
1117
+ case EAnalyticDataType.HOUR: {
1118
+ return getFormattedByInterval(value, AnalyticInterval.HOUR, { isExpandDetail: true });
1119
+ }
1120
+ case EAnalyticDataType.MONTH: {
1121
+ return getFormattedByInterval(value, AnalyticInterval.MONTH, { isExpandDetail: true });
1122
+ }
1123
+ case EAnalyticDataType.YEAR: {
1124
+ return getFormattedByInterval(value, AnalyticInterval.YEAR);
1125
+ }
1126
+ case EAnalyticDataType.WEEK: {
1127
+ return getFormattedByInterval(value, AnalyticInterval.WEEK, { isExpandDetail: true });
1128
+ }
1129
+ case EAnalyticDataType.QUARTER: {
1130
+ return getFormattedByInterval(value, AnalyticInterval.QUARTER, {
1131
+ isExpandDetail: true,
1132
+ });
1133
+ }
1134
+ case EAnalyticDataType.OBJECT:
1135
+ case EAnalyticDataType.ARRAY: {
1136
+ return value;
1137
+ }
1138
+ default:
1139
+ return `${value}`;
1140
+ }
1141
+ };
1142
+
1143
+ const SESSION_KEY = 'sessions';
1144
+ const hasMetricData = (metric) => {
1145
+ const sessions = metric?.[SESSION_KEY];
1146
+ return typeof sessions === 'number' && sessions > 0;
1147
+ };
1148
+
1149
+ const parseRawJson = (raw) => {
1150
+ if (!raw)
1151
+ return undefined;
1152
+ return typeof raw === 'string' ? JSON.parse(raw) : raw;
1153
+ };
1154
+ const parseJsonArray = (raw) => {
1155
+ try {
1156
+ const parsed = parseRawJson(raw);
1157
+ if (!Array.isArray(parsed))
1158
+ return undefined;
1159
+ return parsed;
1160
+ }
1161
+ catch {
1162
+ return undefined;
1163
+ }
1164
+ };
1165
+ const parseBreakdownItems = (raw) => parseJsonArray(raw)?.map((item) => ({ ...item, total: Number(item.total) }));
1166
+
1167
+ const readNumeric = (metric, key) => {
1168
+ const raw = metric?.[key];
1169
+ return typeof raw === 'number' ? raw : 0;
1170
+ };
1171
+
1172
+ const useAnalyticData = (getTextPrice) => {
1173
+ const formatData = ({ value, formatter, name }) => {
1174
+ return formatAnalyticData({ value, formatter, getTextPrice, name });
1175
+ };
1176
+ const computeMetric = ({ metric, previousMetric, metricKey, formatter, }) => {
1177
+ if (!hasMetricData(metric))
1178
+ return { value: 0, change: PLACEHOLDER_VALUE };
1179
+ const currentValue = readNumeric(metric, metricKey);
1180
+ const previousValue = readNumeric(previousMetric, metricKey);
1181
+ const value = formatData({ value: currentValue, formatter, name: metricKey });
1182
+ if (currentValue === 0 && previousValue !== 0)
1183
+ return { value, change: -100 };
1184
+ if (previousValue === 0)
1185
+ return { value, change: PLACEHOLDER_VALUE };
1186
+ const change = ((currentValue - previousValue) / previousValue) * 100;
1187
+ return { value, change };
1188
+ };
1189
+ return { formatData, computeMetric };
1190
+ };
1191
+
1192
+ var GPaginationDirection;
1193
+ (function (GPaginationDirection) {
1194
+ GPaginationDirection["NEXT"] = "NEXT";
1195
+ GPaginationDirection["PREV"] = "PREV";
1196
+ })(GPaginationDirection || (GPaginationDirection = {}));
1197
+
1198
+ const useFormatLineChartData = ({ metricKey, columnTypes }) => {
1199
+ const { formatData } = useAnalyticData();
1200
+ const formatter = metricKey ? columnTypes?.[metricKey] : undefined;
1201
+ const formatValue = (value) => {
1202
+ return String(formatData({ value, formatter }));
1203
+ };
1204
+ const yAxisOptions = {
1205
+ labelFormatter: (value) => {
1206
+ return formatValue(Number(value) || 0);
1207
+ },
1208
+ };
1209
+ return { formatValue, yAxisOptions };
1210
+ };
1211
+
1212
+ const useWindowSize = () => {
1213
+ const [windowSize, setWindowSize] = useState(() => ({
1214
+ width: typeof window !== 'undefined' ? window.innerWidth : 0,
1215
+ height: typeof window !== 'undefined' ? window.innerHeight : 0,
1216
+ }));
1217
+ const windowWidth = useMemo(() => {
1218
+ return {
1219
+ xs: windowSize.width <= 768,
1220
+ md: 768 < windowSize.width && windowSize.width <= 1024,
1221
+ lg: windowSize.width > 1024,
1222
+ xsDown: windowSize.width < 768,
1223
+ '1200Down': windowSize.width < 1200,
1224
+ '1040Down': windowSize.width < 1040,
1225
+ };
1226
+ }, [windowSize.width]);
1227
+ const isMobileTabletView = !windowWidth.lg;
1228
+ const isMobileView = windowWidth.xs;
1229
+ useEffect(() => {
1230
+ const windowSizeHandler = () => {
1231
+ setWindowSize({ width: window.innerWidth, height: window.innerHeight });
1232
+ };
1233
+ window.addEventListener('resize', windowSizeHandler);
1234
+ return () => {
1235
+ window.removeEventListener('resize', windowSizeHandler);
1236
+ };
1237
+ }, []);
1238
+ return { windowSize, windowWidth, isMobileTabletView, isMobileView };
1239
+ };
1240
+
1241
+ const MetricChart = ({ lineChartData, isLoading, isEmptyMetricData, columnTypes, metricKey, }) => {
1242
+ const { formatValue, yAxisOptions } = useFormatLineChartData({ metricKey, columnTypes: columnTypes || {} });
1243
+ if (!metricKey) {
1244
+ return jsx(Fragment, {});
1245
+ }
1246
+ if (isLoading) {
1247
+ return jsx(GChartSkeleton, {});
1248
+ }
1249
+ if (isEmptyMetricData) {
1250
+ return jsx(MetricChartEmpty, { title: "No data yet", description: "Data needs time to gather" });
1251
+ }
1252
+ return (jsx(MetricChartProvider, { children: jsx(LineChart, { data: lineChartData, yAxisOptions: yAxisOptions, theme: "Light", tooltipOptions: {
1253
+ titleFormatter: () => `${ANALYTICS_METRIC_TOOLTIP[metricKey]?.title ?? ''}`,
1254
+ keyFormatter: (value) => {
1255
+ return value;
1256
+ },
1257
+ renderTooltipContent(data) {
1258
+ return jsx(MetricChartTooltip, { data: data, formatValue: formatValue });
1259
+ },
1260
+ }, showLegend: true }) }));
1261
+ };
1262
+
1263
+ var IMAGE_ANALYTIC_EMPTY = "data:image/png;base64,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";
1264
+
1265
+ const MetricChartEmpty = ({ boxProps, minHeight, description, title }) => {
1266
+ 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 })] })] }) }) }) }));
1267
+ };
1268
+
1269
+ const DownIcon8px = () => {
1270
+ 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" }) }) })] }));
1271
+ };
1272
+
1273
+ const UpIcon8px = () => {
1274
+ 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)" }) }) })] }));
1275
+ };
1276
+
1277
+ const MetricPercentage = ({ change }) => {
1278
+ if (typeof change !== 'number') {
1279
+ return jsx("div", { style: { height: '2px', width: '11px', backgroundColor: '#8A8A8A' } });
1280
+ }
1281
+ return (jsxs("div", { style: {
1282
+ display: 'flex',
1283
+ maxHeight: '20px',
1284
+ width: 'fit-content',
1285
+ alignItems: 'center',
1286
+ gap: '4px',
1287
+ borderRadius: '8px',
1288
+ fontSize: '12px',
1289
+ color: change > 0 ? TREND_TONE.POSITIVE : TREND_TONE.NEUTRAL,
1290
+ }, 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)) })] }));
1291
+ };
1292
+
1293
+ const MetricChartTooltip = ({ data, formatValue }) => {
1294
+ const { activeIndex } = data;
1295
+ const currentData = data?.dataSeries[0]?.data[activeIndex];
1296
+ const previousData = data?.dataSeries[1]?.data[activeIndex];
1297
+ const formatPercent = () => {
1298
+ const value = currentData.trend?.value;
1299
+ if (!value)
1300
+ return PLACEHOLDER_VALUE$1;
1301
+ const valueNumber = Number(value.replace(/[%~]/g, ''));
1302
+ if (currentData.trend?.trend === 'negative') {
1303
+ return valueNumber * -1;
1304
+ }
1305
+ return valueNumber;
1306
+ };
1307
+ 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() }) })] })] })] })] }) }) }));
1308
+ };
1309
+
1310
+ const MetricInfoSkeleton = ({ isShowOneLine }) => {
1311
+ if (isShowOneLine) {
1312
+ return (jsx(Box, { width: "40%", children: jsx(SkeletonBodyText, { lines: 1 }) }));
1313
+ }
1314
+ return (jsxs(BlockStack, { gap: "200", children: [jsx(Box, { width: "60%", children: jsx(SkeletonBodyText, { lines: 1 }) }), jsx(Box, { width: "40%", children: jsx(SkeletonBodyText, { lines: 1 }) })] }));
1315
+ };
1316
+
1317
+ const MetricDonutChartSkeleton = () => {
1318
+ return (jsx(Card, { children: jsxs(BlockStack, { gap: "400", children: [jsx(MetricInfoSkeleton, { isShowOneLine: true }), jsx(GChartSkeleton, {})] }) }));
1319
+ };
1320
+
1321
+ 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 })] }) }));
1322
+
1323
+ const MetricInfoBlock = ({ item, isHovered, isLoading, hideComparison, titleVariant = 'headingMd', titleFontWeight, onClickTitle, }) => {
1324
+ const { key, title, totalValue } = item;
1325
+ const tooltip = ANALYTICS_METRIC_TOOLTIP[key];
1326
+ if (isLoading)
1327
+ return jsx(MetricInfoSkeleton, {});
1328
+ return (jsxs(BlockStack, { gap: "200", children: [jsx("div", { className: "hover:cursor-pointer hover:text-[--p-color-text-link-hover]", onClick: (e) => {
1329
+ e?.stopPropagation();
1330
+ onClickTitle?.(key);
1331
+ }, 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 })] }));
1332
+ };
1333
+
1334
+ const MetricChartTab = ({ item, isActive, isLoading, hideComparison, onSelect, onClickTitle, }) => {
1335
+ const [isHovered, setIsHovered] = useState(false);
1336
+ const isHighlighted = isActive || isHovered;
1337
+ 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 }) }) }));
1338
+ };
1339
+
1340
+ const GSelectableMetricChartCard = ({ metricInfo, dataChart, defaultActiveTab, isLoading, isEmptyMetricData, hideComparison, currentPeriodLabel = DEFAULT_CURRENT_PERIOD_LABEL, previousPeriodLabel = DEFAULT_PREVIOUS_PERIOD_LABEL, columnTypes, }) => {
1341
+ const [activeTab, setActiveTab] = useState(defaultActiveTab);
1342
+ const lineChartData = useMemo(() => {
1343
+ const chartData = activeTab ? dataChart[activeTab] : undefined;
1344
+ if (!chartData)
1345
+ return [];
1346
+ const currentSeries = { name: currentPeriodLabel, data: chartData.current };
1347
+ if (hideComparison)
1348
+ return [currentSeries];
1349
+ return [currentSeries, { name: previousPeriodLabel, data: chartData.previous, isComparison: true }];
1350
+ }, [activeTab, dataChart, hideComparison, currentPeriodLabel, previousPeriodLabel]);
1351
+ return (jsxs(Card, { children: [jsx("div", { style: {
1352
+ display: 'grid',
1353
+ gridTemplateColumns: `repeat(${metricInfo.length}, 1fr)`,
1354
+ gap: '16px',
1355
+ marginBottom: '16px',
1356
+ }, 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 })] }));
1357
+ };
1358
+
1359
+ EGroupOperator.OR;
1360
+
1361
+ [
1362
+ {
1363
+ operator: EOperatorField.DEVICE_OPERATOR,
1364
+ singleField: EFilterField.DEVICE,
1365
+ multiField: EFilterField.DEVICES,
1366
+ fieldName: EFilterField.DEVICE,
1367
+ },
1368
+ {
1369
+ operator: EOperatorField.VISITOR_OPERATOR,
1370
+ singleField: EFilterField.VISITOR,
1371
+ multiField: EFilterField.VISITORS,
1372
+ fieldName: EFilterField.VISITOR,
1373
+ },
1374
+ {
1375
+ operator: EOperatorField.TRAFFIC_SOURCE_OPERATOR,
1376
+ singleField: EFilterField.TRAFFIC_SOURCE,
1377
+ multiField: EFilterField.TRAFFIC_SOURCES,
1378
+ fieldName: EFilterField.TRAFFIC_SOURCE,
1379
+ },
1380
+ {
1381
+ operator: EOperatorField.VERSION_OPERATOR,
1382
+ singleField: EFilterField.VERSION,
1383
+ multiField: EFilterField.VERSIONS,
1384
+ fieldName: EFilterField.VERSION,
1385
+ },
1386
+ {
1387
+ operator: EOperatorField.PAGE_OPERATOR,
1388
+ singleField: EFilterField.SINGLE_PAGE,
1389
+ multiField: EFilterField.LIST_PAGE,
1390
+ fieldName: EFilterField.SINGLE_PAGE,
1391
+ },
1392
+ {
1393
+ operator: EOperatorField.CAMPAIGN_ITEM_OPERATOR,
1394
+ singleField: EFilterField.GROUP_CAMPAIGN_ITEM,
1395
+ multiField: EFilterField.GROUP_CAMPAIGN_ITEMS,
1396
+ condition: EFilterField.GROUP_CAMPAIGN,
1397
+ fieldName: EFilterField.SINGLE_CAMPAIGN,
1398
+ },
1399
+ {
1400
+ operatorVal: OPERATOR_IS,
1401
+ singleField: EFilterField.SINGLE_CAMPAIGN,
1402
+ multiField: EFilterField.GROUP_CAMPAIGN,
1403
+ },
1404
+ ];
1405
+
1406
+ const calculatePercentageChange = (current, previous) => {
1407
+ if (current === 0 && previous === 0) {
1408
+ return undefined;
1409
+ }
1410
+ if (previous === 0) {
1411
+ return current > 0 ? '100%' : '0%';
1412
+ }
1413
+ const change = ((current - previous) / previous) * 100;
1414
+ return `${Math.abs(change).toFixed(0)}%`;
1050
1415
  };
1051
- const GSelectorChoice = ({ options, selected, onSelect, maxWidth, minWidth, clearable, setPopoverActive, }) => {
1052
- const { t } = useTranslation();
1053
- const items = useMemo(() => {
1054
- if (!options?.length)
1055
- return [];
1056
- return options.map((option) => ({
1057
- value: option.id,
1058
- label: option.content || '',
1059
- selected: false,
1060
- }));
1061
- }, [options]);
1062
- const handleSelection = useCallback((value) => {
1063
- onSelect(value);
1064
- }, [onSelect]);
1065
- return (jsx(Box, { maxWidth: maxWidth, minWidth: minWidth, paddingBlock: "150", children: jsxs(BlockStack, { children: [jsx(BlockStack, { gap: "0", children: jsx(GCheckbox, { multiple: true, options: items, selected: selected, onChange: handleSelection }) }), clearable && (jsx(Box, { paddingBlock: "150", paddingInline: "200", children: jsx(InlineStack, { blockAlign: "center", align: "start", children: jsx(Button, { disabled: !selected?.length, onClick: () => {
1066
- handleSelection([]);
1067
- setPopoverActive(false);
1068
- }, variant: "plain", children: t('Clear') }) }) }))] }) }));
1416
+ const computeDonutData = ({ name, currentValue, prevValue, hasPreviousData, }) => ({
1417
+ name,
1418
+ data: [{ key: 'value', value: currentValue }],
1419
+ metadata: {
1420
+ trend: {
1421
+ value: hasPreviousData ? calculatePercentageChange(currentValue, prevValue) : undefined,
1422
+ direction: currentValue >= prevValue ? 'upward' : 'downward',
1423
+ trend: currentValue >= prevValue ? 'positive' : 'negative',
1424
+ },
1425
+ },
1426
+ });
1427
+ const getTotalCountByType = (stats, type) => {
1428
+ const item = stats?.find((stat) => stat?.type?.toLowerCase() === type.toLowerCase());
1429
+ return item?.total ?? 0;
1069
1430
  };
1070
- const GSelectorActionList = ({ options, selected, onSelect, helpText, maxWidth, minWidth, setPopoverActive, }) => {
1071
- const handleSelection = useCallback((value) => {
1072
- onSelect(value);
1073
- setPopoverActive(false);
1074
- }, [onSelect, setPopoverActive]);
1075
- const items = useMemo(() => {
1076
- if (!options?.length)
1077
- return [];
1078
- return options.map((option) => ({
1079
- id: option.id,
1080
- content: option.content,
1081
- helpText: option.helpText,
1082
- onAction: () => handleSelection(option.id),
1083
- active: option.active || option.id === selected,
1084
- suffix: (option.active || option.id === selected) && jsx(Icon, { source: SvgCheckIcon, tone: "success" }),
1085
- }));
1086
- }, [options, selected, handleSelection]);
1087
- return (jsx(Box, { maxWidth: maxWidth, minWidth: minWidth, children: jsxs(BlockStack, { gap: "0", children: [jsx(ActionList, { actionRole: "menuitem", items: items }), helpText] }) }));
1431
+ const buildBreakdownDonutData = ({ targets, metricKey, totalsRow, comparisonTotalsRow, sort, }) => {
1432
+ const items = parseBreakdownItems(totalsRow?.[metricKey]);
1433
+ const comparisonItems = parseBreakdownItems(comparisonTotalsRow?.[metricKey]);
1434
+ const hasPreviousData = !!comparisonTotalsRow?.[metricKey];
1435
+ const result = targets.map(({ value, label }) => computeDonutData({
1436
+ name: label,
1437
+ currentValue: getTotalCountByType(items, value),
1438
+ prevValue: getTotalCountByType(comparisonItems, value),
1439
+ hasPreviousData,
1440
+ }));
1441
+ const getValue = (item) => item.data[0]?.value ?? 0;
1442
+ return sort ? [...result].sort((a, b) => getValue(b) - getValue(a)) : result;
1088
1443
  };
1089
1444
 
1090
- const GTextLink = ({ linkAction, isDisabled, disabledFocus, children }) => {
1091
- if (!linkAction || isDisabled) {
1092
- return jsx(Fragment, { children: children });
1445
+ const DONUT_CHART_MIN_HEIGHT = 294;
1446
+ const COMPACT_MAX_WIDTH = 1500;
1447
+ const MetricDonutChartCard = ({ label, metricKey, targets, totalsRow, comparisonTotalsRow, sort, isLoading, isEmptyMetricData, minHeight = DONUT_CHART_MIN_HEIGHT, onClick, }) => {
1448
+ const tooltip = ANALYTICS_METRIC_TOOLTIP[metricKey];
1449
+ const { windowWidth, windowSize } = useWindowSize();
1450
+ const [isHovered, setIsHovered] = useState(false);
1451
+ const data = useMemo(() => buildBreakdownDonutData({ targets, metricKey, totalsRow, comparisonTotalsRow, sort }), [targets, metricKey, totalsRow, comparisonTotalsRow, sort]);
1452
+ if (isLoading) {
1453
+ return jsx(MetricDonutChartSkeleton, {});
1093
1454
  }
1094
- return (jsx("span", { className: cls('GTextLink', { 'GTextLink--disabled-focus': disabledFocus }), children: jsx(Link, { ...linkAction, children: jsx(Fragment, { children: children }) }) }));
1455
+ const formatValue = (value) => {
1456
+ return numberWithCommas(`${value}`);
1457
+ };
1458
+ const handleClickTitle = (event) => {
1459
+ event.stopPropagation();
1460
+ onClick();
1461
+ };
1462
+ const isCompactView = windowWidth.lg && windowSize.width < COMPACT_MAX_WIDTH;
1463
+ 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', {
1464
+ 'max-h-[250px] overflow-hidden': isCompactView,
1465
+ }), 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: {
1466
+ valueFormatter: formatValue,
1467
+ }, labelFormatter: formatValue }) })) })] }) }) }));
1095
1468
  };
1096
1469
 
1097
- const GSkeletonDisplayText = (props) => {
1098
- const height = props.height ?? '50px';
1099
- return (jsxs("div", { className: "Polaris-GSkeletonDisplayText", children: [jsx("style", { children: `.Polaris-GSkeletonDisplayText .Polaris-SkeletonDisplayText__DisplayText { height: ${height} !important; }` }), jsx(SkeletonDisplayText, { maxWidth: "100%", size: "extraLarge" })] }));
1470
+ const SingleMetricChartCard = ({ metricInfo, lineChartData, isLoading, hideComparison, columnTypes, isEmptyMetricData, onClickTitle, }) => {
1471
+ const [isHovered, setIsHovered] = useState(false);
1472
+ 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 })] }) }) }));
1100
1473
  };
1101
1474
 
1102
- /**
1103
- * Helper function to generate a variation class name.
1104
- * @param name - Base name of the class.
1105
- * @param value - Variation value to append.
1106
- * @returns Combined class name.
1107
- */
1108
- function variationName(name, value) {
1109
- return `${name}${value.charAt(0).toUpperCase()}${value.slice(1)}`;
1110
- }
1111
- const GThumbnail = ({ source, alt, size, grayscale, defaultSource = THUMB_PRODUCT_DEFAULT, width = '80', height = '80', classRemoved = false, }) => {
1112
- const sizeClass = size && variationName('Polaris-Thumbnail--size', size);
1113
- const filterClass = grayscale && 'Polaris-GThumbnail--filter';
1114
- const className = cls('Polaris-Thumbnail', sizeClass);
1115
- const thumbnail = (jsx("img", { onError: (e) => {
1116
- e.currentTarget.src = defaultSource;
1117
- }, alt: alt ?? 'Thumbnail', src: `${source ?? defaultSource}`, width: width, height: height, style: {
1118
- '--gp-grayscale-percentage': grayscale || '100%',
1119
- }, className: cls('Polaris-GThumbnail', filterClass) }));
1120
- if (classRemoved)
1121
- return thumbnail;
1122
- return jsx("span", { className: className, children: thumbnail });
1123
- };
1475
+ var IMAGE_FIRST_SESSION = "data:image/png;base64,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";
1124
1476
 
1125
- const SIZE_CLASS = {
1126
- default: 'w-[210px]',
1127
- wide: 'w-[320px]',
1128
- large: 'w-[328px]',
1129
- };
1130
- const ALIGNMENT_MAP = {
1131
- start: 'flex justify-start',
1132
- center: 'flex justify-center',
1133
- end: 'flex justify-end',
1134
- };
1135
- const GTooltipCard = forwardRef((props, ref) => {
1136
- const { tooltip, wrapper = 'div', activatorProps, isHideBorder, alignment, delay = 500, textDecoration = 'none', popoverRef, preferredAlignment = 'left', showArrow = false, } = props;
1137
- const { width = 'default' } = tooltip ?? {};
1138
- const [isMouseEnter, setIsMouseEnter] = useState(false);
1139
- const TooltipCardWrapper = wrapper;
1140
- const sizeClass = SIZE_CLASS[width];
1141
- const timeoutRef = useRef(null);
1142
- const handleMouseEnter = () => {
1143
- timeoutRef.current = setTimeout(() => {
1144
- setIsMouseEnter(true);
1145
- }, delay);
1477
+ var IMAGE_ALL_SESSION = "data:image/png;base64,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";
1478
+
1479
+ const VIEW_BY_OPTIONS = [
1480
+ {
1481
+ id: EAnalyticMode.ALL_SESSION,
1482
+ content: 'All sessions',
1483
+ helpText: 'Count metrics for all sessions where this page shows up anywhere in the journey: before, during, or after other pages.',
1484
+ icon: IMAGE_ALL_SESSION,
1485
+ },
1486
+ {
1487
+ id: EAnalyticMode.FIRST_SESSION,
1488
+ content: 'Entry session only',
1489
+ helpText: 'Count metrics for sessions only where this page was the very first page visited, then track how they moved through the funnel.',
1490
+ icon: IMAGE_FIRST_SESSION,
1491
+ },
1492
+ ];
1493
+ const AnalyticModeSelector = ({ activatorText = 'View by', value, onChange }) => {
1494
+ const options = useMemo(() => {
1495
+ return VIEW_BY_OPTIONS.map((option) => ({
1496
+ ...option,
1497
+ }));
1498
+ }, []);
1499
+ const onSelectMode = (value) => {
1500
+ onChange(value);
1146
1501
  };
1147
- const handleMouseLeave = () => {
1148
- if (timeoutRef.current) {
1149
- clearTimeout(timeoutRef.current);
1150
- timeoutRef.current = null;
1502
+ return (jsx(GViewBySelector, { activatorText: activatorText, options: options, selected: value, onSelect: onSelectMode, maxWidth: "650px" }));
1503
+ };
1504
+
1505
+ const EXCHANGE_RATE_HELP_URL = 'https://help.shopify.com/en/manual/international/pricing/exchange-rates#auto-convert';
1506
+ const CurrencySelector = ({ currencies, selected, preferredAlignment = 'left', activatorText, onSelect, }) => {
1507
+ const { t } = useTranslation();
1508
+ const onSelectRef = useRef(onSelect);
1509
+ const handleSelection = useCallback((value) => {
1510
+ onSelectRef.current?.(value);
1511
+ }, []);
1512
+ const actionItems = useMemo(() => {
1513
+ if (!currencies)
1514
+ return [];
1515
+ const formattedCurrencies = currencies.map((currency) => ({
1516
+ content: currency,
1517
+ id: currency,
1518
+ }));
1519
+ const hasCurrencyDefault = formattedCurrencies.some((item) => item.id === DEFAULT_CURRENCY_ANALYTIC);
1520
+ if (!hasCurrencyDefault) {
1521
+ formattedCurrencies.push({
1522
+ content: DEFAULT_CURRENCY_ANALYTIC,
1523
+ id: DEFAULT_CURRENCY_ANALYTIC,
1524
+ });
1151
1525
  }
1152
- setIsMouseEnter(false);
1153
- };
1154
- useImperativeHandle(ref, () => ({ onClose: handleMouseLeave }));
1155
- return (jsx(TooltipCardWrapper, { className: cls('GTooltipCard cursor-pointer', alignment && ALIGNMENT_MAP[alignment], {
1156
- 'GTooltipCard--text-underline': textDecoration === 'underline',
1157
- }), onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: jsx(Popover, { ref: popoverRef, activator: !isHideBorder ? (jsx(Box, { borderBlockEndWidth: "025", borderStyle: "dashed", borderColor: "border-tertiary", as: wrapper, ...activatorProps, children: props.children })) : (jsx(InlineStack, { children: props.children })), activatorWrapper: wrapper, onClose: () => { }, active: isMouseEnter, preferredPosition: "below", preferredAlignment: preferredAlignment, children: tooltip && (jsx("div", { className: cls(sizeClass, { 'GTooltipCard-arrow': showArrow }), children: jsx(Box, { padding: "400", children: jsxs(BlockStack, { gap: "200", children: [jsxs(BlockStack, { gap: "100", children: [jsx(Text, { as: "span", variant: "headingSm", fontWeight: "semibold", children: tooltip.title }), jsxs(BlockStack, { gap: "200", children: [jsx(Text, { as: "span", variant: "bodyMd", tone: "subdued", fontWeight: "medium", children: jsx("span", { dangerouslySetInnerHTML: { __html: tooltip.content } }) }), tooltip.contentList && (jsx(List, { type: "bullet", children: tooltip.contentList.map((item) => (jsx(List.Item, { children: jsx(Text, { as: "span", variant: "bodyMd", tone: "subdued", fontWeight: "medium", children: item }) }, item))) }))] })] }), tooltip.formula && (jsx("div", { className: "rounded-md font-mono", style: { fontSize: '12px' }, children: tooltip.formula }))] }) }) })) }) }));
1158
- });
1159
- GTooltipCard.displayName = 'GTooltipCard';
1526
+ return sortByConditions(formattedCurrencies, [
1527
+ { attr: 'content', order: 'asc', preferredValue: DEFAULT_CURRENCY_ANALYTIC },
1528
+ ]);
1529
+ }, [currencies]);
1530
+ const actionListItems = useMemo(() => {
1531
+ return actionItems.map((option) => ({
1532
+ id: option.id,
1533
+ content: option.content,
1534
+ onAction: () => handleSelection(option.id),
1535
+ active: option.id === selected,
1536
+ suffix: option.id === selected && jsx(Icon, { source: SvgCheckIcon, tone: "success" }),
1537
+ helpText: option.id === DEFAULT_CURRENCY_ANALYTIC && (jsx(Text, { as: "p", fontWeight: "semibold", children: t('Default') })),
1538
+ }));
1539
+ }, [actionItems, selected, handleSelection, t]);
1540
+ const isHidden = useMemo(() => {
1541
+ if (!actionItems?.length)
1542
+ return true;
1543
+ return actionItems.length === 1 && actionItems[0]?.id === DEFAULT_CURRENCY_ANALYTIC;
1544
+ }, [actionItems]);
1545
+ useEffect(() => {
1546
+ onSelectRef.current = onSelect;
1547
+ });
1548
+ if (isHidden)
1549
+ return null;
1550
+ return (jsx(GSelector, { options: actionListItems, selected: selected, variant: "action-list",
1551
+ // value originates from our CurrencyCode option ids, so the widen-to-string round trip is safe
1552
+ 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: {
1553
+ 1: (text) => (jsx(GTextLink, { linkAction: {
1554
+ url: EXCHANGE_RATE_HELP_URL,
1555
+ target: '_blank',
1556
+ }, children: text }, text + 'text-link')),
1557
+ }, children: t("This will follow Shopify's current exchange rate. [1]Read more[]") }) }) }));
1558
+ };
1160
1559
 
1161
1560
  var MainDateTimePickerAlias;
1162
1561
  (function (MainDateTimePickerAlias) {
@@ -1227,1341 +1626,903 @@ function getDateTimeFilterByAlias(alias) {
1227
1626
 
1228
1627
  const DATE_FORMAT = {
1229
1628
  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
1241
- };
1242
-
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);
1324
- };
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);
1330
- };
1331
- const isMidnight = (date) => {
1332
- return date.hour() === 0 && date.minute() === 0;
1333
- };
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(':');
1340
- };
1341
-
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
- /**
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".
1360
- */
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
- }
1376
- return {
1377
- title: getDateRangeTitle(since, until),
1378
- alias: 'custom',
1379
- };
1380
- }
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
-
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 });
1411
- return {
1412
- title,
1413
- alias: `${item.version}`,
1414
- since,
1415
- until,
1416
- isVersion: true,
1417
- isCurrentVersion,
1418
- description,
1419
- versionId: item.id,
1420
- };
1421
- })
1422
- .filter(Boolean);
1423
- };
1424
-
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);
1437
- }
1438
- if (alias === MainDateTimePickerAlias.LAST_12_MONTHS) {
1439
- return getLast12Months(sinceDate);
1440
- }
1441
- if (alias === MainDateTimePickerAlias.LAST_YEAR) {
1442
- return getLastYear(sinceDate);
1443
- }
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
- };
1463
- };
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
- };
1473
- };
1474
- const getToday = (currentDate) => {
1475
- return {
1476
- since: currentDate.valueOf(),
1477
- until: currentDate.valueOf(),
1478
- };
1479
- };
1480
- const getYesterday = (date) => {
1481
- return {
1482
- since: date.subtract(1, 'day').valueOf(),
1483
- until: date.subtract(1, 'day').valueOf(),
1484
- };
1629
+ MONTH_YEAR: 'MMM YYYY', // Jan 2025
1630
+ FULL: 'MMMM D, YYYY', // January 1, 2025
1631
+ FULL_WITH_TIME: 'MMMM D, YYYY [at] h:mm A', // January 1, 2025 at 12:00 AM
1632
+ SHORT: 'MMM DD, YYYY', // Jan 01, 2025
1633
+ SHORT_NO_PAD: 'MMM D, YYYY', // Jan 1, 2025
1634
+ SHORT_WITH_TIME: 'MMM D, YYYY [at] h:mm A', // Jan 1, 2025 at 12:00 AM
1635
+ MONTH_DAY: 'MMM D', // Jan 1
1636
+ DAY_YEAR: 'D, YYYY', // 1, 2025
1637
+ TIME: 'h:mm A', // 12:00 AM
1638
+ MONTH_DAY_WITH_TIME: 'MMM D [at] h:mm A', // Jan 1 at 12:00 AM
1639
+ YEAR: 'YYYY', // 2025
1485
1640
  };
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
- };
1641
+
1642
+ function parseYearMonthDayDateString(input) {
1643
+ // Date-only strings (e.g. "1970-01-01") are treated as UTC, not local time
1644
+ // when using new Date()
1645
+ // We need to split year, month, day to pass into new Date() separately
1646
+ // to get a localized Date
1647
+ return dayjs(input).valueOf();
1495
1648
  }
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
- };
1649
+ const VALID_YYYY_MM_DD_DATE_REGEX = /^\d{4}-\d{1,2}-\d{1,2}/;
1650
+ function isDate(date) {
1651
+ return !isNaN(new Date(date).getDate());
1501
1652
  }
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
- };
1653
+ function isValidYearMonthDayDateString(date) {
1654
+ return VALID_YYYY_MM_DD_DATE_REGEX.test(date) && isDate(date);
1507
1655
  }
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
- };
1656
+ function isValidDate(date) {
1657
+ return date.length === 10 && isValidYearMonthDayDateString(date);
1658
+ }
1659
+ function formatDate(timestamp, type) {
1660
+ const date = convertDateToTz(timestamp);
1661
+ if (type === 'YMD') {
1662
+ return date.format(DATE_FORMAT.YMD);
1518
1663
  }
1519
- return { month, year };
1664
+ if (type === 'MY') {
1665
+ return date.format(DATE_FORMAT.MONTH_YEAR);
1666
+ }
1667
+ if (type === 'FULL') {
1668
+ return date.format(DATE_FORMAT.FULL);
1669
+ }
1670
+ if (type === 'FULL_WITH_TIME') {
1671
+ return date.format(DATE_FORMAT.FULL_WITH_TIME);
1672
+ }
1673
+ return date.format(DATE_FORMAT.SHORT);
1674
+ }
1675
+ function formatTime(timestamp) {
1676
+ const date = convertDateToTz(timestamp);
1677
+ return date.format(DATE_FORMAT.TIME);
1678
+ }
1679
+ function isSameDayTimestamp(since, until) {
1680
+ const sinceDate = convertDateToTz(since);
1681
+ const untilDate = convertDateToTz(until);
1682
+ return sinceDate.isSame(untilDate, 'day');
1683
+ }
1684
+ function formatTimeRange(data) {
1685
+ const { since, until, format = DATE_FORMAT.TIME, showNow = false } = data;
1686
+ const sinceDate = convertDateToTz(since);
1687
+ const untilDate = convertDateToTz(until);
1688
+ return `${sinceDate.format(format)} - ${showNow ? 'Now' : untilDate.format(format)}`;
1689
+ }
1690
+ function formatDateTimeRange(data) {
1691
+ const { since, until, isShowNow } = data;
1692
+ const sinceDate = convertDateToTz(since);
1693
+ const untilDate = convertDateToTz(until);
1694
+ const isToday = sinceDate.isSame(dayjsTz(), 'day');
1695
+ const startTime = sinceDate.format(DATE_FORMAT.TIME);
1696
+ const endTime = untilDate.format(DATE_FORMAT.TIME);
1697
+ if (isToday) {
1698
+ const formatEndTime = isShowNow ? 'Now' : endTime;
1699
+ return `Today at ${startTime} - ${formatEndTime}`;
1700
+ }
1701
+ if (isShowNow) {
1702
+ return `${sinceDate.format(DATE_FORMAT.SHORT_WITH_TIME)} - Now`;
1703
+ }
1704
+ if (sinceDate.isSame(untilDate, 'day')) {
1705
+ return `${sinceDate.format(DATE_FORMAT.SHORT_WITH_TIME)} - ${endTime}`;
1706
+ }
1707
+ if (sinceDate.isSame(untilDate, 'day')) {
1708
+ const time = formatTimeRange({ since, until });
1709
+ return `${sinceDate.format(DATE_FORMAT.SHORT)} (${time})`;
1710
+ }
1711
+ if (sinceDate.isSame(untilDate, 'year')) {
1712
+ return `${sinceDate.format(DATE_FORMAT.MONTH_DAY_WITH_TIME)} - ${untilDate.format(DATE_FORMAT.MONTH_DAY_WITH_TIME)}, ${untilDate.format(DATE_FORMAT.YEAR)}`;
1713
+ }
1714
+ return `${sinceDate.format(DATE_FORMAT.SHORT_WITH_TIME)} - ${untilDate.format(DATE_FORMAT.SHORT_WITH_TIME)}`;
1715
+ }
1716
+ const formatDayjs = (date, isEndDay = false, formatTemplate) => {
1717
+ // const isUTC = date.isUTC?.() ?? false;
1718
+ // if (isUTC) return date.format();
1719
+ if (isEndDay && isMidnight(date)) {
1720
+ return date.endOf('day').format(formatTemplate);
1721
+ }
1722
+ return date.format(formatTemplate);
1520
1723
  };
1521
-
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,
1724
+ const getEndOfDayBy = (value, formatTemplate) => {
1725
+ if (!value) {
1726
+ return formatDayjs(dayjsTz().endOf('day'), false, formatTemplate);
1727
+ }
1728
+ return formatDayjs(dayjsTz(value).endOf('day'), false, formatTemplate);
1536
1729
  };
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,
1730
+ const isMidnight = (date) => {
1731
+ return date.hour() === 0 && date.minute() === 0;
1732
+ };
1733
+ const formatMs = (ms) => {
1734
+ const totalSeconds = Math.floor(ms / 1000);
1735
+ const hours = Math.floor(totalSeconds / 3600);
1736
+ const minutes = Math.floor((totalSeconds % 3600) / 60);
1737
+ const seconds = totalSeconds % 60;
1738
+ return [hours, minutes, seconds].map((v) => String(v).padStart(2, '0')).join(':');
1577
1739
  };
1578
1740
 
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),
1611
- };
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),
1616
- };
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),
1621
- };
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),
1626
- };
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
- ];
1741
+ function getDateRangeTitle(since, until) {
1742
+ const sinceDate = convertDateToTz(since);
1743
+ const untilDate = convertDateToTz(until);
1744
+ if (sinceDate.isSame(untilDate, 'day')) {
1745
+ return sinceDate.format(DATE_FORMAT.SHORT);
1746
+ }
1747
+ if (sinceDate.isSame(untilDate, 'month') && sinceDate.isSame(untilDate, 'year')) {
1748
+ return `${sinceDate.format(DATE_FORMAT.MONTH_DAY)} - ${untilDate.format(DATE_FORMAT.DAY_YEAR)}`;
1749
+ }
1750
+ if (sinceDate.isSame(untilDate, 'year')) {
1751
+ return `${sinceDate.format(DATE_FORMAT.MONTH_DAY)} - ${untilDate.format(DATE_FORMAT.SHORT_NO_PAD)}`;
1752
+ }
1753
+ return `${sinceDate.format(DATE_FORMAT.SHORT_NO_PAD)} - ${untilDate.format(DATE_FORMAT.SHORT_NO_PAD)}`;
1754
+ }
1755
+ /**
1756
+ * Resolves a { title, alias } pair from a since/until date range.
1757
+ * Matches against known presets (today, last 7 days, …); falls back to
1758
+ * a formatted custom range with alias "custom".
1759
+ */
1760
+ function getDateTimeFilterBase(since, until) {
1761
+ const now = dayjsTz();
1762
+ const sinceDate = convertDateToTz(since);
1763
+ const untilDate = convertDateToTz(until);
1764
+ const mappings = getDateTimeFilterMapping();
1765
+ for (const mapping of Object.values(mappings)) {
1766
+ const range = mapping.getDateRange(now);
1767
+ const expectedSince = convertDateToTz(range.since);
1768
+ const expectedUntil = convertDateToTz(range.until);
1769
+ const isSameSince = sinceDate.isSame(expectedSince, 'day');
1770
+ const isSameUntil = untilDate.isSame(expectedUntil, 'day');
1771
+ if (isSameSince && isSameUntil) {
1772
+ return { title: mapping.title, alias: mapping.alias };
1773
+ }
1774
+ }
1638
1775
  return {
1639
- DATE_TIME_FILTERS,
1640
- LAST_7_DAYS_DATE_RANGE,
1641
- LAST_30_DAYS_DATE_RANGE,
1776
+ title: getDateRangeTitle(since, until),
1777
+ alias: 'custom',
1642
1778
  };
1779
+ }
1780
+ function getVersionDateRangeTitle(data) {
1781
+ const { since, until, isShowNow } = data;
1782
+ const sinceDate = convertDateToTz(since);
1783
+ const isToday = sinceDate.isSame(dayjsTz(), 'day');
1784
+ if (isToday)
1785
+ return getDateTimeFilterByAlias(MainDateTimePickerAlias.TODAY).title;
1786
+ if (isShowNow)
1787
+ return `${sinceDate.format(DATE_FORMAT.SHORT_NO_PAD)} - Now`;
1788
+ return getDateRangeTitle(since, until);
1789
+ }
1790
+ const getVersionDateDescription = ({ since, until, isShowNow }) => {
1791
+ const isSameDay = isSameDayTimestamp(since, until);
1792
+ if (!isSameDay)
1793
+ return undefined;
1794
+ return formatTimeRange({ since, until, showNow: isShowNow });
1643
1795
  };
1644
1796
 
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) => {
1797
+ const convertToDateTimeFilters = (versions) => {
1798
+ const dataVersions = [...versions].sort((a, b) => semverToNum(b.version) - semverToNum(a.version));
1799
+ return dataVersions
1800
+ .map((item) => {
1801
+ if (!item.startedAt)
1802
+ return false;
1803
+ const isCurrentVersion = !item.completedAt;
1804
+ const since = dayjsTzToLocalTZ(item.startedAt).valueOf();
1805
+ const until = isCurrentVersion
1806
+ ? dayjsTzToLocalTZ(getEndOfDayBy()).valueOf()
1807
+ : dayjsTzToLocalTZ(item.completedAt).valueOf();
1808
+ const title = getVersionDateRangeTitle({ since, until, isShowNow: isCurrentVersion });
1809
+ const description = getVersionDateDescription({ since, until, isShowNow: isCurrentVersion });
1666
1810
  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
- }),
1811
+ title,
1812
+ alias: `${item.version}`,
1813
+ since,
1814
+ until,
1815
+ isVersion: true,
1816
+ isCurrentVersion,
1817
+ description,
1818
+ versionId: item.id,
1673
1819
  };
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;
1820
+ })
1821
+ .filter(Boolean);
1714
1822
  };
1715
1823
 
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);
1824
+ const getNoComparison = () => {
1825
+ return {
1826
+ since: 0,
1827
+ until: 0,
1764
1828
  };
1765
- const onChange = ({ end }) => {
1766
- setDate(getMonthAndYearByDateFilter(month, year, end));
1829
+ };
1830
+ const getPreviousPeriod = (value) => {
1831
+ const { since, until, alias } = value;
1832
+ const sinceDate = dayjs(since);
1833
+ const untilDate = dayjs(until);
1834
+ if (alias === MainDateTimePickerAlias.LAST_MONTH) {
1835
+ return getLastMonth(sinceDate);
1836
+ }
1837
+ if (alias === MainDateTimePickerAlias.LAST_12_MONTHS) {
1838
+ return getLast12Months(sinceDate);
1839
+ }
1840
+ if (alias === MainDateTimePickerAlias.LAST_YEAR) {
1841
+ return getLastYear(sinceDate);
1842
+ }
1843
+ const duration = untilDate.diff(sinceDate, 'day') + 1;
1844
+ const previousSince = sinceDate.subtract(duration, 'day');
1845
+ const previousUntil = untilDate.subtract(duration, 'day');
1846
+ return {
1847
+ since: previousSince.valueOf(),
1848
+ until: previousUntil.valueOf(),
1767
1849
  };
1768
- const apply = () => {
1769
- setDateTimePicked(dateRange);
1770
- onApply?.(dateRange);
1850
+ };
1851
+ const createPreviousRange = (subtractAmount, subtractUnit) => (value) => {
1852
+ const { since, until } = value;
1853
+ const sinceDate = dayjs(since);
1854
+ const untilDate = dayjs(until);
1855
+ const duration = untilDate.diff(sinceDate, 'day');
1856
+ const previousSince = sinceDate.subtract(subtractAmount, subtractUnit);
1857
+ const previousUntil = previousSince.add(duration, 'day');
1858
+ return {
1859
+ since: previousSince.valueOf(),
1860
+ until: previousUntil.valueOf(),
1771
1861
  };
1772
- const cancel = () => {
1773
- setDateRange(dateTimePicked);
1862
+ };
1863
+ const getPreviousWeek = createPreviousRange(7, 'day');
1864
+ const getPreviousQuarter = createPreviousRange(3, 'month');
1865
+ const getPreviousMonth = createPreviousRange(1, 'month');
1866
+ const getPreviousYear = createPreviousRange(1, 'year');
1867
+ const createLastDaysRange = (subtractAmount) => (date) => {
1868
+ return {
1869
+ since: date.subtract(subtractAmount, 'day').valueOf(),
1870
+ until: date.valueOf(),
1774
1871
  };
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]);
1872
+ };
1873
+ const getToday = (currentDate) => {
1784
1874
  return {
1785
- month,
1786
- year,
1787
- setDate,
1788
- dateRange,
1789
- apply,
1790
- cancel,
1791
- dateTimePicked,
1792
- onChange,
1793
- onMonthChange,
1794
- onCalendarChange,
1875
+ since: currentDate.valueOf(),
1876
+ until: currentDate.valueOf(),
1795
1877
  };
1796
1878
  };
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,
1879
+ const getYesterday = (date) => {
1880
+ return {
1881
+ since: date.subtract(1, 'day').valueOf(),
1882
+ until: date.subtract(1, 'day').valueOf(),
1808
1883
  };
1809
- return { rangeAddition };
1810
1884
  };
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" })] }));
1885
+ const getLast7Days = createLastDaysRange(6);
1886
+ const getLast30Days = createLastDaysRange(29);
1887
+ const getLast90Days = createLastDaysRange(89);
1888
+ const getLast365Days = createLastDaysRange(364);
1889
+ function getLastMonth(date) {
1890
+ return {
1891
+ since: date.subtract(1, 'month').startOf('month').valueOf(),
1892
+ until: date.subtract(1, 'month').endOf('month').valueOf(),
1893
+ };
1883
1894
  }
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);
1895
+ function getLast12Months(date) {
1891
1896
  return {
1892
- value,
1893
- toggle: useCallback(() => setState((state) => !state), []),
1894
- setTrue: useCallback(() => setState(true), []),
1895
- setFalse: useCallback(() => setState(false), []),
1897
+ since: date.subtract(12, 'month').startOf('month').valueOf(),
1898
+ until: date.subtract(1, 'month').endOf('month').valueOf(),
1896
1899
  };
1897
1900
  }
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
- });
1901
+ function getLastYear(date) {
1902
+ return {
1903
+ since: date.subtract(1, 'year').startOf('year').valueOf(),
1904
+ until: date.subtract(1, 'year').endOf('year').valueOf(),
1911
1905
  };
1912
- const options = rangesAdditions.map((range) => {
1913
- const selected = dateTimePicked.alias === range.alias;
1906
+ }
1907
+ const getMonthAndYearByDateFilter = (month, year, date) => {
1908
+ const endDate = dayjs(date);
1909
+ const endMonthFilter = endDate.month();
1910
+ const endYearFilter = endDate.year();
1911
+ if (endYearFilter !== year || endMonthFilter !== month) {
1912
+ const prev = endDate.subtract(1, 'month');
1914
1913
  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})` })] }))] })),
1914
+ month: prev.month(),
1915
+ year: prev.year(),
1917
1916
  };
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
- }
1917
+ }
1918
+ return { month, year };
1919
+ };
1923
1920
 
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
- });
1936
- };
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
- });
1944
- };
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
- }
1921
+ var CompareDateTimePickerAlias;
1922
+ (function (CompareDateTimePickerAlias) {
1923
+ CompareDateTimePickerAlias["NO_COMPARISON"] = "noComparison";
1924
+ CompareDateTimePickerAlias["PREVIOUS_PERIOD"] = "previousPeriod";
1925
+ CompareDateTimePickerAlias["PREVIOUS_WEEK"] = "previousWeek";
1926
+ CompareDateTimePickerAlias["PREVIOUS_MONTH"] = "previousMonth";
1927
+ CompareDateTimePickerAlias["PREVIOUS_QUARTER"] = "previousQuarter";
1928
+ CompareDateTimePickerAlias["PREVIOUS_YEAR"] = "previousYear";
1929
+ })(CompareDateTimePickerAlias || (CompareDateTimePickerAlias = {}));
1930
+ const PREVIOUS_PERIOD_FILTER = {
1931
+ title: 'Previous period',
1932
+ alias: CompareDateTimePickerAlias.PREVIOUS_PERIOD,
1933
+ since: 0,
1934
+ until: 0,
1935
+ };
1936
+ const DATE_TIME_COMPARISON_FILTERS = [
1937
+ {
1938
+ title: 'No comparison',
1939
+ alias: CompareDateTimePickerAlias.NO_COMPARISON,
1940
+ since: 0,
1941
+ until: 0,
1942
+ },
1943
+ PREVIOUS_PERIOD_FILTER,
1944
+ {
1945
+ title: 'Previous week',
1946
+ alias: CompareDateTimePickerAlias.PREVIOUS_WEEK,
1947
+ since: 0,
1948
+ until: 0,
1949
+ },
1950
+ {
1951
+ title: 'Previous quarter',
1952
+ alias: CompareDateTimePickerAlias.PREVIOUS_QUARTER,
1953
+ since: 0,
1954
+ until: 0,
1955
+ },
1956
+ {
1957
+ title: 'Previous month',
1958
+ alias: CompareDateTimePickerAlias.PREVIOUS_MONTH,
1959
+ since: 0,
1960
+ until: 0,
1961
+ },
1962
+ {
1963
+ title: 'Previous year',
1964
+ alias: CompareDateTimePickerAlias.PREVIOUS_YEAR,
1965
+ since: 0,
1966
+ until: 0,
1967
+ },
1968
+ ];
1969
+ const COMPARE_DATE_TIME_FILTERS_MAP = {
1970
+ [CompareDateTimePickerAlias.NO_COMPARISON]: getNoComparison,
1971
+ [CompareDateTimePickerAlias.PREVIOUS_PERIOD]: getPreviousPeriod,
1972
+ [CompareDateTimePickerAlias.PREVIOUS_WEEK]: getPreviousWeek,
1973
+ [CompareDateTimePickerAlias.PREVIOUS_QUARTER]: getPreviousQuarter,
1974
+ [CompareDateTimePickerAlias.PREVIOUS_MONTH]: getPreviousMonth,
1975
+ [CompareDateTimePickerAlias.PREVIOUS_YEAR]: getPreviousYear,
1976
+ };
1950
1977
 
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 });
1978
+ const useDateTimeFilter = () => {
1979
+ const currentDate = dayjsTzToLocalTZ().startOf('day');
1980
+ const mappings = getDateTimeFilterMapping();
1981
+ const TODAY_CONFIG = mappings[MainDateTimePickerAlias.TODAY];
1982
+ const TODAY_DATE_RANGE = {
1983
+ ...TODAY_CONFIG,
1984
+ ...TODAY_CONFIG.getDateRange(currentDate),
1985
+ };
1986
+ const YESTERDAY_CONFIG = mappings[MainDateTimePickerAlias.YESTERDAY];
1987
+ const YESTERDAY_DATE_RANGE = {
1988
+ ...YESTERDAY_CONFIG,
1989
+ ...YESTERDAY_CONFIG.getDateRange(currentDate),
1962
1990
  };
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
- });
1991
+ const LAST_7_DAYS_CONFIG = mappings[MainDateTimePickerAlias.LAST_7_DAYS];
1992
+ const LAST_7_DAYS_DATE_RANGE = {
1993
+ ...LAST_7_DAYS_CONFIG,
1994
+ ...LAST_7_DAYS_CONFIG.getDateRange(currentDate),
1984
1995
  };
1985
- const apply = () => {
1986
- setCompareDateTimePicked(dateRange);
1987
- onApply?.(dateRange);
1996
+ const LAST_30_DAYS_CONFIG = mappings[MainDateTimePickerAlias.LAST_30_DAYS];
1997
+ const LAST_30_DAYS_DATE_RANGE = {
1998
+ ...LAST_30_DAYS_CONFIG,
1999
+ ...LAST_30_DAYS_CONFIG.getDateRange(currentDate),
1988
2000
  };
1989
- const cancel = () => {
1990
- setDateRange(compareDateTimePicked);
2001
+ const LAST_90_DAYS_CONFIG = mappings[MainDateTimePickerAlias.LAST_90_DAYS];
2002
+ const LAST_90_DAYS_DATE_RANGE = {
2003
+ ...LAST_90_DAYS_CONFIG,
2004
+ ...LAST_90_DAYS_CONFIG.getDateRange(currentDate),
1991
2005
  };
1992
- const onChange = ({ end }) => {
1993
- setDate(getMonthAndYearByDateFilter(month, year, end));
2006
+ const LAST_365_DAYS_CONFIG = mappings[MainDateTimePickerAlias.LAST_365_DAYS];
2007
+ const LAST_365_DAYS_DATE_RANGE = {
2008
+ ...LAST_365_DAYS_CONFIG,
2009
+ ...LAST_365_DAYS_CONFIG.getDateRange(currentDate),
1994
2010
  };
1995
- return {
1996
- month,
1997
- year,
1998
- setDate,
1999
- dateRange,
2000
- apply,
2001
- cancel,
2002
- compareDateTimePicked,
2003
- onChange,
2004
- onMonthChange,
2005
- onCalendarChange,
2011
+ const LAST_MONTH_CONFIG = mappings[MainDateTimePickerAlias.LAST_MONTH];
2012
+ const LAST_MONTH_DATE_RANGE = {
2013
+ ...LAST_MONTH_CONFIG,
2014
+ ...LAST_MONTH_CONFIG.getDateRange(currentDate),
2006
2015
  };
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);
2016
+ const LAST_12_MONTHS_CONFIG = mappings[MainDateTimePickerAlias.LAST_12_MONTHS];
2017
+ const LAST_12_MONTHS_DATE_RANGE = {
2018
+ ...LAST_12_MONTHS_CONFIG,
2019
+ ...LAST_12_MONTHS_CONFIG.getDateRange(currentDate),
2080
2020
  };
2081
- const onChangeDateTimeFilter = (data) => {
2082
- onCalendarChange(data);
2083
- onChange(data);
2021
+ const LAST_YEAR_CONFIG = mappings[MainDateTimePickerAlias.LAST_YEAR];
2022
+ const LAST_YEAR_DATE_RANGE = {
2023
+ ...LAST_YEAR_CONFIG,
2024
+ ...LAST_YEAR_CONFIG.getDateRange(currentDate),
2084
2025
  };
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
- };
2116
-
2117
- const MainTimePicker = (props) => {
2118
- const { rangeAddition, popoverProps, activator, onApply, activatorProps, actionProps } = props;
2119
- 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;
2026
+ const DATE_TIME_FILTERS = [
2027
+ TODAY_DATE_RANGE,
2028
+ YESTERDAY_DATE_RANGE,
2029
+ LAST_7_DAYS_DATE_RANGE,
2030
+ LAST_30_DAYS_DATE_RANGE,
2031
+ LAST_90_DAYS_DATE_RANGE,
2032
+ LAST_365_DAYS_DATE_RANGE,
2033
+ LAST_MONTH_DATE_RANGE,
2034
+ LAST_12_MONTHS_DATE_RANGE,
2035
+ LAST_YEAR_DATE_RANGE,
2036
+ ];
2037
+ return {
2038
+ DATE_TIME_FILTERS,
2039
+ LAST_7_DAYS_DATE_RANGE,
2040
+ LAST_30_DAYS_DATE_RANGE,
2134
2041
  };
2135
- return (jsx(BaseTimePicker, { activatorProps: activatorProps, dateTimeFilters: dateTimeFilters, rangeAddition: rangeAddition, popoverProps: popoverProps, actionProps: actionProps, buttonValue: getButtonValue(), activator: activator, onApply: onApply }));
2136
2042
  };
2137
2043
 
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);
2044
+ const DateTimePickerContext = createContext({
2045
+ dateTimePicked: {
2046
+ since: dayjsTz().valueOf(),
2047
+ until: dayjsTz().valueOf(),
2048
+ title: 'Today',
2049
+ alias: 'today',
2050
+ },
2051
+ compareDateTimePicked: PREVIOUS_PERIOD_FILTER,
2052
+ setDateTimePicked: () => { },
2053
+ setCompareDateTimePicked: () => { },
2054
+ resetDateVersion: () => { },
2055
+ });
2056
+ const DateTimePickerProvider = ({ children, initDate, initDateCompare, }) => {
2057
+ const [dateTimePicked, setDateTimePicked] = useState(initDate || {
2058
+ since: dayjsTz().set('hour', 0).valueOf(),
2059
+ until: dayjsTz().set('hour', 0).valueOf(),
2060
+ title: 'Today',
2061
+ alias: 'today',
2062
+ });
2063
+ const { DATE_TIME_FILTERS } = useDateTimeFilter();
2064
+ const getCompareDateTimePicked = useCallback((alias, source = dateTimePicked) => {
2065
+ return {
2066
+ ...PREVIOUS_PERIOD_FILTER,
2067
+ ...COMPARE_DATE_TIME_FILTERS_MAP[alias]({
2068
+ since: source.since,
2069
+ until: source.until,
2070
+ alias: source.alias,
2071
+ }),
2072
+ };
2073
+ }, [dateTimePicked]);
2074
+ const [compareDateTimePicked, setCompareDateTimePicked] = useState(initDateCompare || getCompareDateTimePicked(CompareDateTimePickerAlias.PREVIOUS_PERIOD));
2075
+ const updateCompareDateTimePicked = useCallback((source) => {
2076
+ if (compareDateTimePicked.alias === 'custom' ||
2077
+ compareDateTimePicked.alias === CompareDateTimePickerAlias.NO_COMPARISON)
2078
+ return;
2079
+ setCompareDateTimePicked(getCompareDateTimePicked(compareDateTimePicked.alias, source));
2080
+ }, [compareDateTimePicked, getCompareDateTimePicked]);
2081
+ const resetDateVersion = () => {
2082
+ const since = dayjs(dateTimePicked.since).startOf('day').valueOf();
2083
+ const until = dayjs(dateTimePicked.until).startOf('day').valueOf();
2084
+ const dateFilter = DATE_TIME_FILTERS.find((filter) => filter.since === since && filter.until === until);
2085
+ setDateTimePicked({
2086
+ ...dateTimePicked,
2087
+ isVersion: false,
2088
+ versionId: undefined,
2089
+ isCurrentVersion: false,
2090
+ description: '',
2091
+ title: dateFilter?.title || dateTimePicked.title,
2092
+ alias: dateFilter?.alias || 'custom',
2093
+ });
2160
2094
  };
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
- }) }) }) }));
2095
+ const onSetDateTimePicked = useCallback((value) => {
2096
+ setDateTimePicked(value);
2097
+ updateCompareDateTimePicked(value);
2098
+ }, [updateCompareDateTimePicked]);
2099
+ return (jsx(DateTimePickerContext.Provider, { value: {
2100
+ dateTimePicked,
2101
+ setDateTimePicked: onSetDateTimePicked,
2102
+ compareDateTimePicked,
2103
+ setCompareDateTimePicked,
2104
+ resetDateVersion,
2105
+ }, children: children }));
2167
2106
  };
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 }))] }));
2107
+ const useDateTimePickerContext = () => {
2108
+ const context = useContext(DateTimePickerContext);
2109
+ if (!context) {
2110
+ throw new Error('useDateTimePickerContext must be used within a DateTimePickerProvider');
2111
+ }
2112
+ return context;
2178
2113
  };
2179
2114
 
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' },
2115
+ const useDateTimePicker = ({ ranges, initialPicked, onApply }) => {
2116
+ const { DATE_TIME_FILTERS } = useDateTimeFilter();
2117
+ const allRanges = ranges || DATE_TIME_FILTERS;
2118
+ const { dateTimePicked, setDateTimePicked } = useDateTimePickerContext();
2119
+ const [dateRange, setDateRange] = useState(dateTimePicked);
2120
+ const [{ month, year }, setDate] = useState({
2121
+ month: dayjs(dateTimePicked.since).month(),
2122
+ year: dayjs(dateTimePicked.since).year(),
2123
+ });
2124
+ useEffect(() => {
2125
+ if (dateTimePicked) {
2126
+ const untilDate = new Date(dateTimePicked.until);
2127
+ const monthDiff = (referenceDate, newDate) => {
2128
+ return newDate.month - referenceDate.month + 12 * (referenceDate.year - newDate.year);
2199
2129
  };
2130
+ monthDiff({ year, month }, {
2131
+ year: untilDate.getFullYear(),
2132
+ month: untilDate.getMonth(),
2133
+ });
2134
+ // if (monthDifference > 1 || monthDifference < 0) {
2135
+ // setDate({
2136
+ // month: untilDate.getMonth(),
2137
+ // year: untilDate.getFullYear(),
2138
+ // });
2139
+ // }
2200
2140
  }
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 }) }) }));
2141
+ }, [dateTimePicked, month, year]);
2142
+ const onMonthChange = (month, year) => {
2143
+ setDate({ month, year });
2210
2144
  };
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 }) }) }));
2145
+ const onCalendarChange = (value) => {
2146
+ const { start, end, alias } = value;
2147
+ const customDateRange = {
2148
+ alias: 'custom',
2149
+ title: 'Custom',
2150
+ since: start.getTime(),
2151
+ until: end.getTime(),
2152
+ };
2153
+ const newDateRange = allRanges.find((range) => {
2154
+ const isSameAlias = range.alias === alias;
2155
+ const isSameUntil = range.until === end.getTime();
2156
+ const isSameSince = range.since === start.getTime();
2157
+ // const isSameVersionId = !!range.versionId && !!versionId && range.versionId === versionId;
2158
+ const isSameTime = isSameSince && isSameUntil;
2159
+ return isSameAlias || isSameTime;
2160
+ });
2161
+ const finalDateRange = newDateRange || initialPicked || customDateRange;
2162
+ setDateRange(finalDateRange);
2213
2163
  };
2214
- const renderInputComponent = () => {
2215
- return isMultipleSelect ? checkBoxComponent() : radioComponent();
2164
+ const onChange = ({ end }) => {
2165
+ setDate(getMonthAndYearByDateFilter(month, year, end));
2216
2166
  };
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 }));
2167
+ const apply = () => {
2168
+ setDateTimePicked(dateRange);
2169
+ onApply?.(dateRange);
2250
2170
  };
2251
- const yAxisOptions = {
2252
- labelFormatter: (value) => {
2253
- return formatValue(Number(value) || 0);
2254
- },
2171
+ const cancel = () => {
2172
+ setDateRange(dateTimePicked);
2255
2173
  };
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
2174
  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;
2175
+ if (dateTimePicked) {
2176
+ setDateRange(dateTimePicked);
2177
+ setDate({
2178
+ month: dayjs(dateTimePicked.since).month(),
2179
+ year: dayjs(dateTimePicked.since).year(),
2180
+ });
2351
2181
  }
2352
- return valueNumber;
2182
+ }, [dateTimePicked]);
2183
+ return {
2184
+ month,
2185
+ year,
2186
+ setDate,
2187
+ dateRange,
2188
+ apply,
2189
+ cancel,
2190
+ dateTimePicked,
2191
+ onChange,
2192
+ onMonthChange,
2193
+ onCalendarChange,
2353
2194
  };
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
2195
  };
2386
2196
 
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)
2197
+ const useVersionDateTimeFilters = (versions) => {
2198
+ const { t } = useTranslation();
2199
+ const rangers = useMemo(() => {
2200
+ if (!versions?.length)
2392
2201
  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 })] }));
2202
+ return convertToDateTimeFilters(versions);
2203
+ }, [versions]);
2204
+ const rangeAddition = {
2205
+ title: t('Experiment periods'),
2206
+ rangers,
2207
+ };
2208
+ return { rangeAddition };
2404
2209
  };
2405
2210
 
2406
- const calculatePercentageChange = (current, previous) => {
2407
- if (current === 0 && previous === 0) {
2408
- return undefined;
2211
+ function DateTimeFilterInputs({ onBlur, dateRange, setDateTimePicked }) {
2212
+ const [isFocus, setIsFocus] = useState(false);
2213
+ const [inputValues, setInputValues] = useState({});
2214
+ const formatDisplayDate = useCallback((timestamp, isEnd = false) => {
2215
+ if (!dateRange.isVersion || (isEnd && dateRange.isCurrentVersion))
2216
+ return formatDate(timestamp, 'FULL');
2217
+ return formatDate(timestamp, 'FULL_WITH_TIME');
2218
+ }, [dateRange.isVersion, dateRange.isCurrentVersion]);
2219
+ useEffect(() => {
2220
+ if (isFocus)
2221
+ return;
2222
+ setInputValues({
2223
+ since: formatDisplayDate(dateRange.since),
2224
+ until: formatDisplayDate(dateRange.until, true),
2225
+ });
2226
+ }, [dateRange, formatDisplayDate]);
2227
+ function handleStartInputValueChange(value) {
2228
+ setInputValues((prevState) => {
2229
+ return { ...prevState, since: value };
2230
+ });
2231
+ if (isValidDate(value)) {
2232
+ const newSinceDate = convertDateToTz(value).startOf('day');
2233
+ const untilDate = convertDateToTz(dateRange.until).endOf('day');
2234
+ const endDate = newSinceDate.isAfter(untilDate) ? newSinceDate.endOf('day') : untilDate;
2235
+ setDateTimePicked({
2236
+ start: dayjsTzToLocalTZ(newSinceDate).toDate(),
2237
+ end: dayjsTzToLocalTZ(endDate).toDate(),
2238
+ });
2239
+ }
2409
2240
  }
2410
- if (previous === 0) {
2411
- return current > 0 ? '100%' : '0%';
2241
+ function handleEndInputValueChange(value) {
2242
+ setInputValues((prevState) => ({ ...prevState, until: value }));
2243
+ if (isValidDate(value)) {
2244
+ const nowEndOfDay = dayjsTz().endOf('day');
2245
+ const newUntilDate = convertDateToTz(value).endOf('day');
2246
+ const clampedUntil = newUntilDate.isAfter(nowEndOfDay) ? nowEndOfDay : newUntilDate;
2247
+ const sinceDate = convertDateToTz(dateRange.since).startOf('day');
2248
+ const startDate = clampedUntil.isBefore(sinceDate) ? clampedUntil.startOf('day') : sinceDate;
2249
+ setDateTimePicked({
2250
+ start: dayjsTzToLocalTZ(startDate).toDate(),
2251
+ end: dayjsTzToLocalTZ(clampedUntil).toDate(),
2252
+ });
2253
+ }
2412
2254
  }
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;
2255
+ function handleInputBlur() {
2256
+ setIsFocus(false);
2257
+ setInputValues({
2258
+ since: formatDisplayDate(dateRange.since),
2259
+ until: formatDisplayDate(dateRange.until, true),
2260
+ });
2261
+ onBlur && onBlur();
2262
+ }
2263
+ function handleFocusStartInput() {
2264
+ setIsFocus(true);
2265
+ setInputValues({
2266
+ ...inputValues,
2267
+ since: formatDate(dateRange.since, 'YMD'),
2268
+ });
2269
+ }
2270
+ function handleFocusEndInput() {
2271
+ setIsFocus(true);
2272
+ setInputValues({
2273
+ ...inputValues,
2274
+ until: formatDate(dateRange.until, 'YMD'),
2275
+ });
2276
+ }
2277
+ return (jsxs(InlineGrid, { gap: "200", columns: "1fr auto 1fr", children: [jsx(TextField, { role: "combobox", label: 'Since', labelHidden: true,
2278
+ // prefix={<Icon source={CalendarIcon} />}
2279
+ 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,
2280
+ // prefix={<Icon source={CalendarIcon} />}
2281
+ value: dateRange.until ? inputValues.until : 'MMMM D, YYYY', onChange: handleEndInputValueChange, onBlur: () => handleInputBlur(), onFocus: () => handleFocusEndInput(), autoComplete: "off" })] }));
2282
+ }
2283
+
2284
+ function DateTimeFilterAddition(props) {
2285
+ const { setDateTimePicked, dateTimePicked, rangeAddition, allRanges } = props;
2286
+ const { value: isExpanded, toggle: toggleExpanded } = useToggle(true);
2287
+ const rangesAdditions = rangeAddition?.rangers || [];
2288
+ const handleChangeFilterByOption = (value) => {
2289
+ const alias = value[0];
2290
+ const result = allRanges.find((range) => range.alias === alias) || allRanges[0];
2291
+ setDateTimePicked({
2292
+ start: dayjsTz(result?.since).toDate(),
2293
+ end: dayjsTz(result?.until).toDate(),
2294
+ alias: result?.alias,
2295
+ });
2296
+ };
2297
+ const options = rangesAdditions.map((range) => {
2298
+ const selected = dateTimePicked.alias === range.alias;
2299
+ return {
2300
+ value: range.alias,
2301
+ 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})` })] }))] })),
2302
+ };
2303
+ });
2304
+ if (!rangeAddition || rangesAdditions.length === 0)
2305
+ return;
2306
+ 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 }) })] }));
2307
+ }
2308
+
2309
+ function DateTimeFilters(props) {
2310
+ const { setDateTimePicked, dateTimePicked, allRanges, isCompare } = props;
2311
+ const { DATE_TIME_FILTERS } = useDateTimeFilter();
2312
+ const { mdDown } = useBreakpoints();
2313
+ const rangesDefault = isCompare ? [...DATE_TIME_COMPARISON_FILTERS] : [...DATE_TIME_FILTERS];
2314
+ const handleChangeFilterBySelect = (value) => {
2315
+ const result = allRanges.find(({ title, alias }) => title === value || alias === value) || allRanges[0];
2316
+ setDateTimePicked({
2317
+ start: dayjsTz(result?.since).toDate(),
2318
+ end: dayjsTz(result?.until).toDate(),
2319
+ alias: result?.alias,
2320
+ });
2321
+ };
2322
+ const handleChangeFilterByOption = (value) => {
2323
+ const result = allRanges.find((range) => range.alias === value[0]) || allRanges[0];
2324
+ setDateTimePicked({
2325
+ start: dayjsTz(result?.since).toDate(),
2326
+ end: dayjsTz(result?.until).toDate(),
2327
+ alias: result?.alias,
2328
+ });
2329
+ };
2330
+ 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) => ({
2331
+ value: range.alias,
2332
+ label: range.title,
2333
+ })), selected: dateTimePicked ? [dateTimePicked.alias] : [], onChange: (value) => handleChangeFilterByOption(value) })] }) }) })) }));
2334
+ }
2335
+
2336
+ const useCompareDateTimePicker = ({ ranges, onApply }) => {
2337
+ const allRanges = ranges || DATE_TIME_COMPARISON_FILTERS;
2338
+ const { compareDateTimePicked, setCompareDateTimePicked } = useDateTimePickerContext();
2339
+ const { dateTimePicked: mainDateRange } = useDateTimePickerContext();
2340
+ const [dateRange, setDateRange] = useState(compareDateTimePicked);
2341
+ const [{ month, year }, setDate] = useState({
2342
+ month: dayjsTz(compareDateTimePicked.since).month(),
2343
+ year: dayjsTz(compareDateTimePicked.since).year(),
2344
+ });
2345
+ const onMonthChange = (month, year) => {
2346
+ setDate({ month, year });
2347
+ };
2348
+ const onCalendarChange = ({ start, end, alias }) => {
2349
+ const newDateRange = allRanges.find((range) => {
2350
+ return range.alias === alias;
2351
+ });
2352
+ // If the alias is not found, set the custom date range
2353
+ if (!newDateRange) {
2354
+ setDateRange({
2355
+ alias: 'custom',
2356
+ title: 'Custom',
2357
+ since: start.getTime(),
2358
+ until: end.getTime(),
2359
+ });
2360
+ return;
2361
+ }
2362
+ setDateRange({
2363
+ ...newDateRange,
2364
+ ...COMPARE_DATE_TIME_FILTERS_MAP[alias]({
2365
+ since: mainDateRange.since,
2366
+ until: mainDateRange.until,
2367
+ }),
2368
+ });
2369
+ };
2370
+ const apply = () => {
2371
+ setCompareDateTimePicked(dateRange);
2372
+ onApply?.(dateRange);
2373
+ };
2374
+ const cancel = () => {
2375
+ setDateRange(compareDateTimePicked);
2376
+ };
2377
+ const onChange = ({ end }) => {
2378
+ setDate(getMonthAndYearByDateFilter(month, year, end));
2379
+ };
2380
+ return {
2381
+ month,
2382
+ year,
2383
+ setDate,
2384
+ dateRange,
2385
+ apply,
2386
+ cancel,
2387
+ compareDateTimePicked,
2388
+ onChange,
2389
+ onMonthChange,
2390
+ onCalendarChange,
2391
+ };
2443
2392
  };
2444
2393
 
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, {});
2394
+ const BaseTimePicker = (props) => {
2395
+ const { dateTimeFilters, rangeAddition, popoverProps, activatorProps, actionProps, isCompare, buttonValue, activator, } = props;
2396
+ const initialPicked = rangeAddition?.initialPicked;
2397
+ const ranges = [...(dateTimeFilters || []), ...(rangeAddition?.rangers || [])];
2398
+ const useHookDateTimePicker = isCompare ? useCompareDateTimePicker : useDateTimePicker;
2399
+ const { month, year, dateRange, apply, cancel, onMonthChange, onCalendarChange, onChange } = useHookDateTimePicker({
2400
+ ranges,
2401
+ initialPicked,
2402
+ onApply: props.onApply,
2403
+ });
2404
+ const { t } = useTranslation();
2405
+ const { mdDown, lgUp } = useBreakpoints();
2406
+ const shouldShowMultiMonth = lgUp;
2407
+ const rawTooltipContent = useMemo(() => {
2408
+ // Only show tooltip when selecting Period (isVersion)
2409
+ if (!dateRange.isVersion || !dateRange.since || !dateRange.until)
2410
+ return;
2411
+ return formatDateTimeRange({
2412
+ since: dateRange.since,
2413
+ until: dateRange.until,
2414
+ isShowNow: dateRange.isCurrentVersion,
2415
+ });
2416
+ }, [dateRange.since, dateRange.until, dateRange.isVersion, dateRange.isCurrentVersion]);
2417
+ const [popoverActive, setPopoverActive] = useState(false);
2418
+ // Freeze tooltip content while popover is open to prevent button remount (focus/CSS loss)
2419
+ const datePickerRef = useRef(null);
2420
+ const tooltipContentRef = useRef(rawTooltipContent);
2421
+ if (!popoverActive)
2422
+ tooltipContentRef.current = rawTooltipContent;
2423
+ const tooltipContent = tooltipContentRef.current;
2424
+ //@ts-ignore
2425
+ function nodeContainsDescendant(rootNode, descendant) {
2426
+ if (rootNode === descendant) {
2427
+ return true;
2428
+ }
2429
+ let parent = descendant.parentNode;
2430
+ while (parent != null) {
2431
+ if (parent === rootNode) {
2432
+ return true;
2433
+ }
2434
+ parent = parent.parentNode;
2435
+ }
2436
+ return false;
2454
2437
  }
2455
- const formatValue = (value) => {
2456
- return numberWithCommas(`${value}`);
2438
+ //@ts-ignore
2439
+ function isNodeWithinPopover(node) {
2440
+ return datePickerRef?.current ? nodeContainsDescendant(datePickerRef.current, node) : false;
2441
+ }
2442
+ //@ts-ignore
2443
+ function handleInputBlur({ relatedTarget }) {
2444
+ const isRelatedTargetWithinPopover = relatedTarget != null && isNodeWithinPopover(relatedTarget);
2445
+ // If focus moves from the TextField to the Popover
2446
+ // we don't want to close the popover
2447
+ if (isRelatedTargetWithinPopover) {
2448
+ return;
2449
+ }
2450
+ setPopoverActive(false);
2451
+ }
2452
+ function applyFunc() {
2453
+ apply();
2454
+ setPopoverActive(false);
2455
+ }
2456
+ function cancelFunc() {
2457
+ cancel();
2458
+ setPopoverActive(false);
2459
+ }
2460
+ const handleTogglePopover = () => {
2461
+ if (isCompare) {
2462
+ return;
2463
+ }
2464
+ setPopoverActive(!popoverActive);
2457
2465
  };
2458
- const handleClickTitle = (event) => {
2459
- event.stopPropagation();
2460
- onClick();
2466
+ const onChangeDateTimeFilter = (data) => {
2467
+ onCalendarChange(data);
2468
+ onChange(data);
2461
2469
  };
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 }) })) })] }) }) }));
2470
+ 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: {
2471
+ xs: '1fr',
2472
+ md: 'max-content max-content',
2473
+ }, 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
2474
+ ? undefined
2475
+ : {
2476
+ start: dayjs(dateRange.since).toDate(),
2477
+ end: dayjs(dateRange.until).toDate(),
2478
+ }, onMonthChange: onMonthChange, onChange: onCalendarChange, multiMonth: shouldShowMultiMonth, allowRange: true, disableDatesAfter: dayjsTzToDate() }) }), actionProps && (jsx(GButton, { ...actionProps, onClick: () => {
2479
+ setPopoverActive(false);
2480
+ actionProps.onClick?.();
2481
+ } }))] }) })] }) }) }), 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
2482
  };
2469
2483
 
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 })] }) }) }));
2484
+ const CompareTimePicker = (props) => {
2485
+ const { rangeAddition, popoverProps } = props;
2486
+ const initialPicked = rangeAddition?.initialPicked;
2487
+ const dateTimeFilters = DATE_TIME_COMPARISON_FILTERS;
2488
+ const ranges = [...dateTimeFilters, ...(rangeAddition?.rangers || [])];
2489
+ const { t } = useTranslation();
2490
+ const { compareDateTimePicked } = useCompareDateTimePicker({ ranges, initialPicked });
2491
+ const buttonValue = useMemo(() => {
2492
+ if (compareDateTimePicked.alias === CompareDateTimePickerAlias.NO_COMPARISON) {
2493
+ return t('No comparison');
2494
+ }
2495
+ return t('Compare to: {{value}}', {
2496
+ value: getDateRangeTitle(compareDateTimePicked.since, compareDateTimePicked.until),
2497
+ });
2498
+ }, [compareDateTimePicked, t]);
2499
+ return (jsx(BaseTimePicker, { dateTimeFilters: dateTimeFilters, rangeAddition: rangeAddition, popoverProps: popoverProps, isCompare: true, buttonValue: buttonValue }));
2473
2500
  };
2474
2501
 
2475
- var IMAGE_FIRST_SESSION = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAXAAAAC4CAMAAADNC0dgAAAAulBMVEUAAAD39/f39/f39/f39/f39/f8/Pz39/fb5P+WrPj///8aHB3j4+P09vfKzdDo6Ojy8vLl5ebd5f7h6P7n7Pzr6+vu7u5wcXLx8/nt8PsxNDn7+/vGxscphFrEzOS8yfakt/je5Pecsfjh4+zQ2fZjZnDr7vdSVFaHm95UnXt4sZd6f41Ek2/H0visvfTk7+vZ3OSOkJZXY4ipqqvX6OBIUm+u0cGRwKqpqqo3i2Vvc4CwtcGFkba82cvy+RBRAAAAB3RSTlMAduu/IJ8QQSls1wAACLJJREFUeNrs1kEKwEAIBEHdNfH/P84lhJzmtsJA1xMaUeN1516NQ9bOir/ajcOuX/JkuAes/Ho3RiS9tTPFi30yZlVEXI0xO6Iag242+KwMPvBROziZo1Y0RhFcI7g7gmsEd0dwjeDuCK4R3B3BNYK7I7hGcHcE1wjujuAawd0RXCO4O4JrBHdHcI3g7giuEdwdwTWCuyO4RnB3BNcI7u5h1+x2nIaBMHo5ThkrcVpbLVGbJlsVFthQEFqEBO//WnizTUddb6bEPyJInKv26kvPTMZu4v/Cef4L/9dJK1wanVtMAYmRRSHBZYY5KYUbhRfydM4Lrc4ZWgIx05x0wg0iKlP0baERMU9jw6BF5VrnV3WdbU4q4TJH1LAYqJ6+G4hOoWxMUT1ngLEhfffNOCeRcKkw73WTcoOoITKmrypRFYhKAsw4J7Zw8l0tXgAqmnHyULwIqXJUBcB8c9IIt2oXLqBCpgrvgTB97802J4lw3fe3CyBG7L6i9+Bi0wFgrjkphEvE3reLielCDR7cu90AzDUnhfB8uEKHSsVrcYP5SAogSoCZ5iQQLlFVixGKeC2uEMZSNBqAmeYkEG7QOJf2+Ovc4tGar6DGcwBEAJhnTgLhudsS37f3sZtPu3Pr86chpZ9c88xJIByxcnz/+HaZKRqioLByPGy/XxZnAzDPnPjCJeZjvi0y1hBH5Xr4QCkaYJ458YUXqGluk+8z4CucH63kgVLmmRNR+PFQ1/t91g3Cf2wfyXc8FevNalmWzZDy6V6Sh3gpcrOyMUK8mjMH4U29z55ph5543Frj5DtEBWmwEnqaIeV+ey/JQxzh69VSiPGcvy98/dBmF1pUCzJOvv0XTfJQioFyECGfTJCHAOFUVCG4nL8u/Fk3ccKKjJPv0P3D+skDgViRCfIQWlZJRU2TEy780GbX7Gjn+nj2TeSeO2S5FNfcISwuJshD4G5/XYqkOeHCj132Alo1Ld9e+AZU4MPGFUH/Z+UH8uD5f5aqmjQnXDi1N9Hi+NMH49yDviIa5okNt9nn2zttTrjwOnuNGnXU53iyF+G2XjEmwu/57EaIZDnhwsm3S3sKf4LMNx7feoXX3FoJkTYnXPg+G6EbGSra4wrJt9t6eRXhNiLfaXPChdfZKDUq8H8LyM8TQqEJf3NKvtPmhAt/yBjqV99zM1tCD9+iVKhDzwbQ/E6bEy78kFlY4/n1SQ7lda5gyZqIdfplLUTanHDhxzbj6U6IWl7OKinE3f4IU1ndNIEGrqqKzRKmIksxPccAQ3zh++wWbW2Vo9Ln03inzhYBJiLFLe4UYj6cYLSf7xohNjCRlfDIKROdvOIHCk+3O2HPaddlTxxgGqW4SdkovGB1W1wVngOcz1kBQ2Thx332h7Rd17Xt5dsaGBgTLE1z19P09ZmuohR+OcyPiS28zjx5gCmUwhMJE9gIT5bAES6cXzF5mBaPbcJt8QRlZVo8rnCa4OEtnsjE1Cm+EanqGi6c36K8//rMe7bFwWHq5vjw5WPPLo6KpUcKU9cUwpvsNb6+OfOWNd4A4bVZ+3jJ2cUYr9I/hd+Ahgvnl8yP9treWd7eMF4D4TNRflIOuQhYNjd8in9dw4XzE+U3e+ffmzYMhOH9dypZotZ2h4OqxKA0TJqogGnSBP3+n2sLK7mxiEvI2/No1ecLvOjxxflxtpklj5OGaU+NB2LGzCgnOQVee3ZEChNl9Wx9wzBJ8vDyE3tqvCZmxIxymlPAtWeAlO5ziobwdN4jfPpTNF7RMKwsvMkRXBgahodSujdnjQpf9QmfsHFgEjeSCs4psIs9x1Is9YJXeNkrnI1Lwsd9t+rkFNDF7rAUQ73gFR5E4Zv2eQq7a/oe4ZwD3TUdkNJAAnGE386SF75CwvMe4ZxTILOrBVIaYqxLuRGENzx8/82mFd6BCBfOOahwICWS8EwQznw+Lzw7kFLDOjtyTw332ZG1KJxzzqgw1R01pFkLcSL/AjMs5d0Iv8uOfIGEd1mv+4TfvhHhhAjHp5RODjilvAHhARMeiD6Et1yPcA8IBx8L5ZT4j4XlUOHYiw8o3BOjJ9ySgLbw/eQvMhY+oucj3M66OQX0ag+lGFXhcoNtlnybMM0rGtCBEGbXTs4MeudOgZRYH6/qcw2f5bRlmSRbnc+zm39zduDnWSBF9/MsE6QWm9BoQxoQzO40Z1mBDQggRb0BIa9Ked7+aNk+I19n5QV/+91jy24Pt9iAlFgttvkNANBEFsCayDL/v4lMi/G+Aw3GxzFhgZhYOyBW44VXNByjbILH9doXAvnxS91qGo6LY8JqDSsuHC/xki4gvfLFnI5EcOF4iV+4ByKPY8LqDyu+IF9vBsdV2AtNePVhxYXTk9IjCq4C33KCD2vcTVX4HZNxUSovtfrDim8b1JxQGBul8rz6sOLCqdRYi48X37jNZbnCqywmHDde0ihSE+VKd+qXES6cguINk/FG0TfjIvjGj+9QrG/GW0XfjFP3jQunlYJvYB43ngCcgm+1I5hkFhVBpE5FhHwp4c8nmHBgT/JTTSi5URAxamCtJ4hPhFIFzfJmF4oimNzKKcalhIELp7pcCLpXLALDW23d/coR3Swcp66Cnm7GO1XdrFyjutUO+2VCOSeQs4f9MsbmsAfhsF+27QnnlY+znq/KEA6qQ1lWNengc2cP2o2xLvcpqZD+STnGvFbKxx+Y/mKHjmkAAGAgCPl3XQefrpeABL6EVwnfhNcJ34TXCd+E1wnfhNcJ34TXCd+E1wnfhNcJ34TXCd+E1wnfhNcJ34TXCd+E1wnfhNcJ34TXCd+E1wnfhNcJ34TXCd+E1wnfhNcJ34Rfe/VyAjEQA0G09LF12vzTXTA2vs3NDQP9QihEa3cOvubgu3PwNQffnYOvOfjuHFyMHBNKakyoiDGh4BwTarwpSgfQfpsy2YBXXCfAxYWCW3hVBDLg0cfYx6qBV0f5zL/yy4oTLn9JSvy4U7oaTQAAAABJRU5ErkJggg==";
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);
2502
+ const MainTimePicker = (props) => {
2503
+ const { rangeAddition, popoverProps, activator, onApply, activatorProps, actionProps } = props;
2504
+ const { DATE_TIME_FILTERS } = useDateTimeFilter();
2505
+ const dateTimeFilters = DATE_TIME_FILTERS;
2506
+ const additionalRanges = rangeAddition?.rangers || [];
2507
+ const initialPicked = rangeAddition?.initialPicked;
2508
+ const ranges = [...dateTimeFilters, ...additionalRanges];
2509
+ const { dateTimePicked } = useDateTimePicker({ ranges, initialPicked });
2510
+ const getButtonValue = () => {
2511
+ if (dateTimePicked.isVersion && additionalRanges.length > 0) {
2512
+ const time = dateTimePicked.description ? `at ${dateTimePicked.description}` : '';
2513
+ return `Period: ${dateTimePicked.title} ${time}`;
2514
+ }
2515
+ if (dateTimePicked.alias === 'custom') {
2516
+ return getDateRangeTitle(dateTimePicked.since, dateTimePicked.until);
2517
+ }
2518
+ return dateTimePicked.title;
2508
2519
  };
2509
- return (jsx(GViewBySelector, { activatorText: activatorText, options: options, selected: value, onSelect: onSelectMode, maxWidth: "650px" }));
2520
+ return (jsx(BaseTimePicker, { activatorProps: activatorProps, dateTimeFilters: dateTimeFilters, rangeAddition: rangeAddition, popoverProps: popoverProps, actionProps: actionProps, buttonValue: getButtonValue(), activator: activator, onApply: onApply }));
2510
2521
  };
2511
2522
 
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[]") }) }) }));
2523
+ const GTimePicker = (props) => {
2524
+ const { isCompare, ...timePickerProps } = props;
2525
+ return (jsxs(InlineStack, { gap: "200", children: [jsx(MainTimePicker, { ...timePickerProps }), isCompare && (jsx(CompareTimePicker, { rangeAddition: timePickerProps.rangeAddition, popoverProps: timePickerProps.popoverProps }))] }));
2565
2526
  };
2566
2527
 
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 };
2528
+ export { ANALYTICS_METRIC_TOOLTIP, AnalyticModeSelector, CAMPAIGN_BACKGROUND_MAIN, CHART_MIN_HEIGHT, COMPARE_DATE_TIME_FILTERS_MAP, CompareDateTimePickerAlias, CurrencySelector, DATE_TIME_COMPARISON_FILTERS, DEFAULT_CURRENCY_ANALYTIC, DEFAULT_CURRENT_PERIOD_LABEL, DEFAULT_PREVIOUS_PERIOD_LABEL, DateTimeFilterInputs, DateTimeFilters, DateTimePickerContext, DateTimePickerProvider, GSelectableMetricChartCard, GTimePicker, MainDateTimePickerAlias, MetricDonutChartCard, PLACEHOLDER_VALUE$1 as PLACEHOLDER_VALUE, PREVIOUS_PERIOD_FILTER, SERIES_COLORS, SingleMetricChartCard, TARGET_CHANNEL, TARGET_DEVICES, TARGET_VISITOR, THUMB_PRODUCT_DEFAULT, TREND_TONE, 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 };