@gem-sdk/analytics 1.0.0-dev.21 → 1.0.0-dev.9

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 (197) hide show
  1. package/dist/esm/components/index.d.ts +0 -3
  2. package/dist/esm/constants/breakdown-targets.d.ts +1 -1
  3. package/dist/esm/constants/index.d.ts +0 -1
  4. package/dist/esm/core/gemxql/builder/clauses/mode-query.d.ts +1 -1
  5. package/dist/esm/core/gemxql/builder/clauses/time-query.d.ts +1 -2
  6. package/dist/esm/core/gemxql/builder/helpers/date-query-helpers.d.ts +1 -1
  7. package/dist/esm/core/gemxql/helpers/extractQueryData.d.ts +1 -1
  8. package/dist/esm/core/gemxql/helpers/getTimeDimension.d.ts +1 -1
  9. package/dist/esm/core/gemxql/hooks/useAnalyticData.d.ts +1 -4
  10. package/dist/esm/core/gemxql/index.d.ts +6 -3
  11. package/dist/esm/core/gemxql/types/analytic-mode.d.ts +5 -0
  12. package/dist/esm/core/gemxql/types/date-filter.d.ts +10 -0
  13. package/dist/esm/core/gemxql/types/index.d.ts +3 -0
  14. package/dist/esm/{utils → core/gemxql/utils}/analytics.d.ts +1 -0
  15. package/dist/esm/{utils → core/gemxql/utils}/dayjs.d.ts +0 -2
  16. package/dist/esm/gemxql.js +205 -347
  17. package/dist/esm/gemxql.mjs +205 -347
  18. package/dist/esm/hooks/index.d.ts +1 -3
  19. package/dist/esm/index.d.ts +2 -4
  20. package/dist/esm/index.js +467 -2133
  21. package/dist/esm/index.mjs +467 -2133
  22. package/dist/esm/providers/index.d.ts +0 -2
  23. package/dist/esm/shared/charts/components/GPolarisViz/components/ChartErrorBoundary/ChartErrorBoundary.d.ts +1 -1
  24. package/dist/esm/shared/charts/components/GPolarisViz/components/TooltipWrapper/utilities/getDonutChartTooltipPosition.d.ts +1 -1
  25. package/dist/esm/shared/charts/components/GPolarisViz/components/TooltipWrapper/utilities/getLineChartTooltipPosition.d.ts +1 -1
  26. package/dist/esm/shared/components/index.d.ts +0 -11
  27. package/dist/esm/types/index.d.ts +0 -3
  28. package/dist/esm/types.js +1 -31
  29. package/dist/esm/types.mjs +1 -31
  30. package/dist/esm/utils/index.d.ts +0 -3
  31. package/dist/style.css +1 -1
  32. package/dist/umd/esm/components/index.d.ts +0 -3
  33. package/dist/umd/esm/constants/breakdown-targets.d.ts +1 -1
  34. package/dist/umd/esm/constants/index.d.ts +0 -1
  35. package/dist/umd/esm/core/gemxql/builder/clauses/mode-query.d.ts +1 -1
  36. package/dist/umd/esm/core/gemxql/builder/clauses/time-query.d.ts +1 -2
  37. package/dist/umd/esm/core/gemxql/builder/helpers/date-query-helpers.d.ts +1 -1
  38. package/dist/umd/esm/core/gemxql/helpers/extractQueryData.d.ts +1 -1
  39. package/dist/umd/esm/core/gemxql/helpers/getTimeDimension.d.ts +1 -1
  40. package/dist/umd/esm/core/gemxql/hooks/useAnalyticData.d.ts +1 -4
  41. package/dist/umd/esm/core/gemxql/index.d.ts +6 -3
  42. package/dist/umd/esm/core/gemxql/types/analytic-mode.d.ts +5 -0
  43. package/dist/umd/esm/core/gemxql/types/date-filter.d.ts +10 -0
  44. package/dist/umd/esm/core/gemxql/types/index.d.ts +3 -0
  45. package/dist/umd/esm/{utils → core/gemxql/utils}/analytics.d.ts +1 -0
  46. package/dist/umd/esm/{utils → core/gemxql/utils}/dayjs.d.ts +0 -2
  47. package/dist/umd/esm/hooks/index.d.ts +1 -3
  48. package/dist/umd/esm/index.d.ts +2 -4
  49. package/dist/umd/esm/providers/index.d.ts +0 -2
  50. package/dist/umd/esm/shared/charts/components/GPolarisViz/components/ChartErrorBoundary/ChartErrorBoundary.d.ts +1 -1
  51. package/dist/umd/esm/shared/charts/components/GPolarisViz/components/TooltipWrapper/utilities/getDonutChartTooltipPosition.d.ts +1 -1
  52. package/dist/umd/esm/shared/charts/components/GPolarisViz/components/TooltipWrapper/utilities/getLineChartTooltipPosition.d.ts +1 -1
  53. package/dist/umd/esm/shared/components/index.d.ts +0 -11
  54. package/dist/umd/esm/types/index.d.ts +0 -3
  55. package/dist/umd/esm/utils/index.d.ts +0 -3
  56. package/dist/umd/gemxql.js +1 -1
  57. package/dist/umd/index.js +1 -1
  58. package/dist/umd/types.js +1 -1
  59. package/package.json +2 -5
  60. package/dist/esm/components/AnalyticMode/AnalyticModeSelector.d.ts +0 -13
  61. package/dist/esm/components/AnalyticMode/index.d.ts +0 -2
  62. package/dist/esm/components/CurrencySelector/CurrencySelector.d.ts +0 -10
  63. package/dist/esm/components/CurrencySelector/index.d.ts +0 -2
  64. package/dist/esm/components/GTimePicker/GTimePicker.d.ts +0 -17
  65. package/dist/esm/components/GTimePicker/components/BaseTimePicker.d.ts +0 -10
  66. package/dist/esm/components/GTimePicker/components/CompareTimePicker.d.ts +0 -5
  67. package/dist/esm/components/GTimePicker/components/DateTimeFilterAddition.d.ts +0 -2
  68. package/dist/esm/components/GTimePicker/components/DateTimeFilterInputs.d.ts +0 -9
  69. package/dist/esm/components/GTimePicker/components/DateTimeFilters.d.ts +0 -15
  70. package/dist/esm/components/GTimePicker/components/MainTimePicker.d.ts +0 -3
  71. package/dist/esm/components/GTimePicker/components/index.d.ts +0 -2
  72. package/dist/esm/components/GTimePicker/constants/compareDateTimePicker.d.ts +0 -12
  73. package/dist/esm/components/GTimePicker/constants/datePicker.d.ts +0 -14
  74. package/dist/esm/components/GTimePicker/constants/index.d.ts +0 -2
  75. package/dist/esm/components/GTimePicker/constants/mainDataTimePicker.d.ts +0 -14
  76. package/dist/esm/components/GTimePicker/contexts/DateTimePickerProvider.d.ts +0 -15
  77. package/dist/esm/components/GTimePicker/contexts/index.d.ts +0 -1
  78. package/dist/esm/components/GTimePicker/helpers/date-range-info.d.ts +0 -16
  79. package/dist/esm/components/GTimePicker/helpers/index.d.ts +0 -4
  80. package/dist/esm/components/GTimePicker/helpers/parse-date.d.ts +0 -24
  81. package/dist/esm/components/GTimePicker/helpers/time-picker.d.ts +0 -76
  82. package/dist/esm/components/GTimePicker/helpers/version.d.ts +0 -2
  83. package/dist/esm/components/GTimePicker/hooks/index.d.ts +0 -3
  84. package/dist/esm/components/GTimePicker/hooks/useCompareDateTimePicker.d.ts +0 -25
  85. package/dist/esm/components/GTimePicker/hooks/useDateTimeFilter.d.ts +0 -18
  86. package/dist/esm/components/GTimePicker/hooks/useDateTimePicker.d.ts +0 -30
  87. package/dist/esm/components/GTimePicker/hooks/useVersionDateTimeFilters.d.ts +0 -9
  88. package/dist/esm/components/GTimePicker/index.d.ts +0 -7
  89. package/dist/esm/components/GTimePicker/types/index.d.ts +0 -38
  90. package/dist/esm/constants/currency.d.ts +0 -2
  91. package/dist/esm/hooks/publish/index.d.ts +0 -2
  92. package/dist/esm/hooks/publish/useStickyDetectById.d.ts +0 -8
  93. package/dist/esm/hooks/publish/useStickyFilterBoxProps.d.ts +0 -6
  94. package/dist/esm/hooks/useFetchCurrencyRates.d.ts +0 -1
  95. package/dist/esm/hooks/useToggle.d.ts +0 -12
  96. package/dist/esm/providers/ConvertMoneyProvider.d.ts +0 -13
  97. package/dist/esm/shared/components/GActivatorPopover/GActivatorPopover.d.ts +0 -23
  98. package/dist/esm/shared/components/GActivatorPopover/index.d.ts +0 -1
  99. package/dist/esm/shared/components/GButton/GButton.d.ts +0 -19
  100. package/dist/esm/shared/components/GButton/index.d.ts +0 -1
  101. package/dist/esm/shared/components/GCheckbox/GCheckbox.d.ts +0 -39
  102. package/dist/esm/shared/components/GCheckbox/index.d.ts +0 -1
  103. package/dist/esm/shared/components/GChoice/ChoiceHelpText.d.ts +0 -4
  104. package/dist/esm/shared/components/GChoice/GChoice.d.ts +0 -44
  105. package/dist/esm/shared/components/GChoice/index.d.ts +0 -2
  106. package/dist/esm/shared/components/GClickable/GClickable.d.ts +0 -10
  107. package/dist/esm/shared/components/GClickable/index.d.ts +0 -1
  108. package/dist/esm/shared/components/GDiv/GDiv.d.ts +0 -7
  109. package/dist/esm/shared/components/GDiv/index.d.ts +0 -1
  110. package/dist/esm/shared/components/GI18NText/GI18NText.d.ts +0 -2
  111. package/dist/esm/shared/components/GI18NText/index.d.ts +0 -2
  112. package/dist/esm/shared/components/GI18NText/types.d.ts +0 -6
  113. package/dist/esm/shared/components/GOptionList/GOptionList.d.ts +0 -11
  114. package/dist/esm/shared/components/GOptionList/index.d.ts +0 -1
  115. package/dist/esm/shared/components/GSelector/GSelector.d.ts +0 -27
  116. package/dist/esm/shared/components/GSelector/index.d.ts +0 -1
  117. package/dist/esm/shared/components/GTextLink/GTextLink.d.ts +0 -9
  118. package/dist/esm/shared/components/GTextLink/index.d.ts +0 -1
  119. package/dist/esm/shared/components/GViewBySelector/GViewBySelector.d.ts +0 -17
  120. package/dist/esm/shared/components/GViewBySelector/index.d.ts +0 -1
  121. package/dist/esm/stores/currencyRatesStore.d.ts +0 -7
  122. package/dist/esm/stores/index.d.ts +0 -2
  123. package/dist/esm/types/analytic-mode.d.ts +0 -5
  124. package/dist/esm/types/currency.d.ts +0 -329
  125. package/dist/esm/utils/currency.d.ts +0 -5
  126. package/dist/esm/utils/sort.d.ts +0 -13
  127. package/dist/umd/esm/components/AnalyticMode/AnalyticModeSelector.d.ts +0 -13
  128. package/dist/umd/esm/components/AnalyticMode/index.d.ts +0 -2
  129. package/dist/umd/esm/components/CurrencySelector/CurrencySelector.d.ts +0 -10
  130. package/dist/umd/esm/components/CurrencySelector/index.d.ts +0 -2
  131. package/dist/umd/esm/components/GTimePicker/GTimePicker.d.ts +0 -17
  132. package/dist/umd/esm/components/GTimePicker/components/BaseTimePicker.d.ts +0 -10
  133. package/dist/umd/esm/components/GTimePicker/components/CompareTimePicker.d.ts +0 -5
  134. package/dist/umd/esm/components/GTimePicker/components/DateTimeFilterAddition.d.ts +0 -2
  135. package/dist/umd/esm/components/GTimePicker/components/DateTimeFilterInputs.d.ts +0 -9
  136. package/dist/umd/esm/components/GTimePicker/components/DateTimeFilters.d.ts +0 -15
  137. package/dist/umd/esm/components/GTimePicker/components/MainTimePicker.d.ts +0 -3
  138. package/dist/umd/esm/components/GTimePicker/components/index.d.ts +0 -2
  139. package/dist/umd/esm/components/GTimePicker/constants/compareDateTimePicker.d.ts +0 -12
  140. package/dist/umd/esm/components/GTimePicker/constants/datePicker.d.ts +0 -14
  141. package/dist/umd/esm/components/GTimePicker/constants/index.d.ts +0 -2
  142. package/dist/umd/esm/components/GTimePicker/constants/mainDataTimePicker.d.ts +0 -14
  143. package/dist/umd/esm/components/GTimePicker/contexts/DateTimePickerProvider.d.ts +0 -15
  144. package/dist/umd/esm/components/GTimePicker/contexts/index.d.ts +0 -1
  145. package/dist/umd/esm/components/GTimePicker/helpers/date-range-info.d.ts +0 -16
  146. package/dist/umd/esm/components/GTimePicker/helpers/index.d.ts +0 -4
  147. package/dist/umd/esm/components/GTimePicker/helpers/parse-date.d.ts +0 -24
  148. package/dist/umd/esm/components/GTimePicker/helpers/time-picker.d.ts +0 -76
  149. package/dist/umd/esm/components/GTimePicker/helpers/version.d.ts +0 -2
  150. package/dist/umd/esm/components/GTimePicker/hooks/index.d.ts +0 -3
  151. package/dist/umd/esm/components/GTimePicker/hooks/useCompareDateTimePicker.d.ts +0 -25
  152. package/dist/umd/esm/components/GTimePicker/hooks/useDateTimeFilter.d.ts +0 -18
  153. package/dist/umd/esm/components/GTimePicker/hooks/useDateTimePicker.d.ts +0 -30
  154. package/dist/umd/esm/components/GTimePicker/hooks/useVersionDateTimeFilters.d.ts +0 -9
  155. package/dist/umd/esm/components/GTimePicker/index.d.ts +0 -7
  156. package/dist/umd/esm/components/GTimePicker/types/index.d.ts +0 -38
  157. package/dist/umd/esm/constants/currency.d.ts +0 -2
  158. package/dist/umd/esm/hooks/publish/index.d.ts +0 -2
  159. package/dist/umd/esm/hooks/publish/useStickyDetectById.d.ts +0 -8
  160. package/dist/umd/esm/hooks/publish/useStickyFilterBoxProps.d.ts +0 -6
  161. package/dist/umd/esm/hooks/useFetchCurrencyRates.d.ts +0 -1
  162. package/dist/umd/esm/hooks/useToggle.d.ts +0 -12
  163. package/dist/umd/esm/providers/ConvertMoneyProvider.d.ts +0 -13
  164. package/dist/umd/esm/shared/components/GActivatorPopover/GActivatorPopover.d.ts +0 -23
  165. package/dist/umd/esm/shared/components/GActivatorPopover/index.d.ts +0 -1
  166. package/dist/umd/esm/shared/components/GButton/GButton.d.ts +0 -19
  167. package/dist/umd/esm/shared/components/GButton/index.d.ts +0 -1
  168. package/dist/umd/esm/shared/components/GCheckbox/GCheckbox.d.ts +0 -39
  169. package/dist/umd/esm/shared/components/GCheckbox/index.d.ts +0 -1
  170. package/dist/umd/esm/shared/components/GChoice/ChoiceHelpText.d.ts +0 -4
  171. package/dist/umd/esm/shared/components/GChoice/GChoice.d.ts +0 -44
  172. package/dist/umd/esm/shared/components/GChoice/index.d.ts +0 -2
  173. package/dist/umd/esm/shared/components/GClickable/GClickable.d.ts +0 -10
  174. package/dist/umd/esm/shared/components/GClickable/index.d.ts +0 -1
  175. package/dist/umd/esm/shared/components/GDiv/GDiv.d.ts +0 -7
  176. package/dist/umd/esm/shared/components/GDiv/index.d.ts +0 -1
  177. package/dist/umd/esm/shared/components/GI18NText/GI18NText.d.ts +0 -2
  178. package/dist/umd/esm/shared/components/GI18NText/index.d.ts +0 -2
  179. package/dist/umd/esm/shared/components/GI18NText/types.d.ts +0 -6
  180. package/dist/umd/esm/shared/components/GOptionList/GOptionList.d.ts +0 -11
  181. package/dist/umd/esm/shared/components/GOptionList/index.d.ts +0 -1
  182. package/dist/umd/esm/shared/components/GSelector/GSelector.d.ts +0 -27
  183. package/dist/umd/esm/shared/components/GSelector/index.d.ts +0 -1
  184. package/dist/umd/esm/shared/components/GTextLink/GTextLink.d.ts +0 -9
  185. package/dist/umd/esm/shared/components/GTextLink/index.d.ts +0 -1
  186. package/dist/umd/esm/shared/components/GViewBySelector/GViewBySelector.d.ts +0 -17
  187. package/dist/umd/esm/shared/components/GViewBySelector/index.d.ts +0 -1
  188. package/dist/umd/esm/stores/currencyRatesStore.d.ts +0 -7
  189. package/dist/umd/esm/stores/index.d.ts +0 -2
  190. package/dist/umd/esm/types/analytic-mode.d.ts +0 -5
  191. package/dist/umd/esm/types/currency.d.ts +0 -329
  192. package/dist/umd/esm/utils/currency.d.ts +0 -5
  193. package/dist/umd/esm/utils/sort.d.ts +0 -13
  194. /package/dist/esm/{types → core/gemxql/types}/breakdown-items.d.ts +0 -0
  195. /package/dist/esm/hooks/{publish/useWindowSize.d.ts → useWindowSize.d.ts} +0 -0
  196. /package/dist/umd/esm/{types → core/gemxql/types}/breakdown-items.d.ts +0 -0
  197. /package/dist/umd/esm/hooks/{publish/useWindowSize.d.ts → useWindowSize.d.ts} +0 -0
@@ -1,17 +1,13 @@
1
1
  "use client"
2
2
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
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';
3
+ import '@tanstack/react-query';
5
4
  import dayjs from 'dayjs';
6
- export { default as dayjs } from 'dayjs';
7
- import quarterOfYear from 'dayjs/plugin/quarterOfYear.js';
8
- import timezone from 'dayjs/plugin/timezone.js';
9
- import utc from 'dayjs/plugin/utc.js';
10
- import { useTranslation } from 'react-i18next';
11
- import { create } from 'zustand';
12
- import { useQuery } from '@tanstack/react-query';
5
+ import quarterOfYear from 'dayjs/plugin/quarterOfYear';
6
+ import timezone from 'dayjs/plugin/timezone';
7
+ import utc from 'dayjs/plugin/utc';
8
+ import React, { useMemo, forwardRef, useState, useRef, useImperativeHandle, useEffect } from 'react';
9
+ import { Box, SkeletonDisplayText, Popover, InlineStack, BlockStack, Text, List, Card, SkeletonBodyText, Icon } from '@shopify/polaris';
13
10
  import { PolarisVizProvider, LineChart, DonutChart } from '@shopify/polaris-viz';
14
- import chartStyle from '@shopify/polaris-viz/build/esm/styles.css?url';
15
11
 
16
12
  var EMetricKey;
17
13
  (function (EMetricKey) {
@@ -127,895 +123,8 @@ const ANALYTICS_METRIC_TOOLTIP = {
127
123
  },
128
124
  };
129
125
 
130
- var EAnalyticMode;
131
- (function (EAnalyticMode) {
132
- EAnalyticMode["ALL_SESSION"] = "ALL_SESSION";
133
- EAnalyticMode["FIRST_SESSION"] = "FIRST_SESSION";
134
- EAnalyticMode["PAGE_ONLY"] = "PAGE_ONLY";
135
- })(EAnalyticMode || (EAnalyticMode = {}));
136
-
137
- var EVisitorType;
138
- (function (EVisitorType) {
139
- EVisitorType["NEW"] = "new";
140
- EVisitorType["RETURNING"] = "returning";
141
- })(EVisitorType || (EVisitorType = {}));
142
- var EDeviceType;
143
- (function (EDeviceType) {
144
- EDeviceType["DESKTOP"] = "desktop";
145
- EDeviceType["MOBILE"] = "mobile";
146
- EDeviceType["TABLET"] = "tablet";
147
- })(EDeviceType || (EDeviceType = {}));
148
- var ETrafficSourceType;
149
- (function (ETrafficSourceType) {
150
- ETrafficSourceType["DIRECT"] = "direct";
151
- ETrafficSourceType["EMAIL"] = "email";
152
- ETrafficSourceType["REFERRAL"] = "referral";
153
- ETrafficSourceType["ORGANIC_SOCIAL"] = "organic-social";
154
- ETrafficSourceType["ORGANIC_SEARCH"] = "organic-search";
155
- ETrafficSourceType["PAID_SOCIAL"] = "paid-social";
156
- ETrafficSourceType["PAID_SEARCH"] = "paid-search";
157
- ETrafficSourceType["SMS"] = "sms";
158
- })(ETrafficSourceType || (ETrafficSourceType = {}));
159
-
160
- const TARGET_VISITOR = [
161
- { value: EVisitorType.NEW, label: 'New' },
162
- { value: EVisitorType.RETURNING, label: 'Returning' },
163
- ];
164
- const TARGET_DEVICES = [
165
- { value: EDeviceType.DESKTOP, label: 'Desktop' },
166
- { value: EDeviceType.TABLET, label: 'Tablet' },
167
- { value: EDeviceType.MOBILE, label: 'Mobile' },
168
- ];
169
- const TARGET_CHANNEL = [
170
- { value: ETrafficSourceType.DIRECT, label: 'Direct' },
171
- { value: ETrafficSourceType.EMAIL, label: 'Email' },
172
- { value: ETrafficSourceType.REFERRAL, label: 'Referral' },
173
- { value: ETrafficSourceType.ORGANIC_SOCIAL, label: 'Organic social' },
174
- { value: ETrafficSourceType.ORGANIC_SEARCH, label: 'Organic search' },
175
- { value: ETrafficSourceType.PAID_SOCIAL, label: 'Paid social' },
176
- { value: ETrafficSourceType.PAID_SEARCH, label: 'Paid search' },
177
- { value: ETrafficSourceType.SMS, label: 'SMS' },
178
- ];
179
-
180
- const CAMPAIGN_BACKGROUND_MAIN = {
181
- ORIGIN: '#2C7DFF',
182
- VARIANT: '#F34A70',
183
- };
184
-
185
- const DEFAULT_CURRENT_PERIOD_LABEL = 'Current';
186
- const DEFAULT_PREVIOUS_PERIOD_LABEL = 'Previous';
187
- const CHART_MIN_HEIGHT = 228;
188
- const SERIES_COLORS = {
189
- current: 'rgba(64, 176, 230, 1)',
190
- comparison: 'rgba(161, 202, 231, 1)',
191
- all: ['#2C7DFF', '#F34A70'],
192
- };
193
- const TREND_TONE = {
194
- POSITIVE: '#007F5F',
195
- NEUTRAL: '#4A4A4A',
196
- };
197
- const PLACEHOLDER_VALUE$1 = '-';
198
-
199
- const DEFAULT_CURRENCY_ANALYTIC = 'USD';
200
-
201
- var THUMB_PRODUCT_DEFAULT = "data:image/svg+xml;base64,PHN2ZwogIHdpZHRoPSI5MCIKICBoZWlnaHQ9IjcyIgogIHZpZXdCb3g9IjAgMCA5MCA3MiIKICBmaWxsPSJub25lIgogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKPgogIDxwYXRoCiAgICBkPSJNNDguNzUgMzQuNUM0OS45OTI2IDM0LjUgNTEgMzMuNDkyNiA1MSAzMi4yNUM1MSAzMS4wMDc0IDQ5Ljk5MjYgMzAgNDguNzUgMzBDNDcuNTA3NCAzMCA0Ni41IDMxLjAwNzQgNDYuNSAzMi4yNUM0Ni41IDMzLjQ5MjYgNDcuNTA3NCAzNC41IDQ4Ljc1IDM0LjVaIgogICAgZmlsbD0iIzYxNjE2MSIKICAvPgogIDxwYXRoCiAgICBmaWxsUnVsZT0iZXZlbm9kZCIKICAgIGNsaXBSdWxlPSJldmVub2RkIgogICAgZD0iTTQzLjUyNjggMjYuMjVINDYuNDczMkM0Ny42OTI0IDI2LjI1IDQ4LjY3NTggMjYuMjUgNDkuNDcyMiAyNi4zMTVDNTAuMjkyMiAyNi4zODIgNTEuMDEyNCAyNi41MjM2IDUxLjY3ODcgMjYuODYzMUM1Mi43MzcxIDI3LjQwMjQgNTMuNTk3NiAyOC4yNjI5IDU0LjEzNjkgMjkuMzIxM0M1NC40NzY0IDI5Ljk4NzYgNTQuNjE4IDMwLjcwNzggNTQuNjg1IDMxLjUyNzhDNTQuNzUgMzIuMzI0MiA1NC43NSAzMy4zMDc2IDU0Ljc1IDM0LjUyNjhWMzcuNDczMkM1NC43NSAzOC42OTI0IDU0Ljc1IDM5LjY3NTggNTQuNjg1IDQwLjQ3MjJDNTQuNjE4IDQxLjI5MjIgNTQuNDc2NCA0Mi4wMTI0IDU0LjEzNjkgNDIuNjc4N0M1My41OTc2IDQzLjczNzEgNTIuNzM3MSA0NC41OTc2IDUxLjY3ODcgNDUuMTM2OUM1MS4wMTI0IDQ1LjQ3NjQgNTAuMjkyMiA0NS42MTggNDkuNDcyMiA0NS42ODVDNDguNjc1OCA0NS43NSA0Ny42OTI0IDQ1Ljc1IDQ2LjQ3MzIgNDUuNzVINDMuNTI2OEM0Mi4zMDc2IDQ1Ljc1IDQxLjMyNDIgNDUuNzUgNDAuNTI3OCA0NS42ODVDMzkuNzA3OCA0NS42MTggMzguOTg3NiA0NS40NzY0IDM4LjMyMTMgNDUuMTM2OUMzNy4yNjI5IDQ0LjU5NzYgMzYuNDAyNCA0My43MzcxIDM1Ljg2MzEgNDIuNjc4N0MzNS41MjM2IDQyLjAxMjQgMzUuMzgyIDQxLjI5MjIgMzUuMzE1IDQwLjQ3MjJDMzUuMjUgMzkuNjc1OCAzNS4yNSAzOC42OTI0IDM1LjI1IDM3LjQ3MzJWMzQuNTI2OEMzNS4yNSAzMy4zMDc2IDM1LjI1IDMyLjMyNDIgMzUuMzE1IDMxLjUyNzhDMzUuMzgyIDMwLjcwNzggMzUuNTIzNiAyOS45ODc2IDM1Ljg2MzEgMjkuMzIxM0MzNi40MDI0IDI4LjI2MjkgMzcuMjYyOSAyNy40MDI0IDM4LjMyMTMgMjYuODYzMUMzOC45ODc2IDI2LjUyMzYgMzkuNzA3OCAyNi4zODIgNDAuNTI3OCAyNi4zMTVDNDEuMzI0MiAyNi4yNSA0Mi4zMDc2IDI2LjI1IDQzLjUyNjggMjYuMjVaTTQwLjcxMSAyOC41NTc2QzQwLjAzMDIgMjguNjEzMiAzOS42MzkxIDI4LjcxNjkgMzkuMzQyOCAyOC44Njc5QzM4LjcwNzcgMjkuMTkxNCAzOC4xOTE0IDI5LjcwNzcgMzcuODY3OSAzMC4zNDI4QzM3LjcxNjkgMzAuNjM5MSAzNy42MTMyIDMxLjAzMDIgMzcuNTU3NiAzMS43MTFDMzcuNTAwOSAzMi40MDUgMzcuNSAzMy4yOTYzIDM3LjUgMzQuNTc1VjM2LjcxNzdMMzguNTg0MiAzNS40MTY3QzM5LjU3MjQgMzQuMjMwOSA0MS4zNjU1IDM0LjE0OTYgNDIuNDU2OSAzNS4yNDFMNDYuNSAzOS4yODQxTDQ4LjI2OTQgMzcuNTE0NkM0OS4zNzU3IDM2LjQwODMgNTEuMTk4IDM2LjUwOTMgNTIuMTc1NCAzNy43MzA5TDUyLjQ5OTUgMzguMTM2MUM1Mi41IDM3LjkxMzEgNTIuNSAzNy42NzY1IDUyLjUgMzcuNDI1VjM0LjU3NUM1Mi41IDMzLjI5NjMgNTIuNDk5MSAzMi40MDUgNTIuNDQyNCAzMS43MTFDNTIuMzg2OCAzMS4wMzAyIDUyLjI4MzEgMzAuNjM5MSA1Mi4xMzIxIDMwLjM0MjhDNTEuODA4NiAyOS43MDc3IDUxLjI5MjMgMjkuMTkxNCA1MC42NTcyIDI4Ljg2NzlDNTAuMzYwOSAyOC43MTY5IDQ5Ljk2OTggMjguNjEzMiA0OS4yODkgMjguNTU3NkM0OC41OTUgMjguNTAwOSA0Ny43MDM3IDI4LjUgNDYuNDI1IDI4LjVINDMuNTc1QzQyLjI5NjMgMjguNSA0MS40MDUgMjguNTAwOSA0MC43MTEgMjguNTU3NlpNMzcuNTU3NiA0MC4yODlDMzcuNTU0MyA0MC4yNDkyIDM3LjU1MTMgNDAuMjA4OCAzNy41NDg0IDQwLjE2NzhDMzcuNTcxMSA0MC4xNDQ4IDM3LjU5MzEgNDAuMTIwNiAzNy42MTQyIDQwLjA5NTNMNDAuMzEyNyAzNi44NTcxQzQwLjQ1MzkgMzYuNjg3NyA0MC43MSAzNi42NzYxIDQwLjg2NTkgMzYuODMyTDQ1LjcwNDUgNDEuNjcwNkM0Ni4xNDM4IDQyLjEwOTkgNDYuODU2MSA0Mi4xMDk5IDQ3LjI5NTUgNDEuNjcwNkw0OS44NjA0IDM5LjEwNTZDNTAuMDE4NSAzOC45NDc2IDUwLjI3ODggMzguOTYyIDUwLjQxODQgMzkuMTM2NUw1Mi4yMzc3IDQxLjQxMDdDNTIuMjA1NiA0MS41MDEgNTIuMTcwNCA0MS41ODIyIDUyLjEzMjEgNDEuNjU3MkM1MS44MDg2IDQyLjI5MjMgNTEuMjkyMyA0Mi44MDg2IDUwLjY1NzIgNDMuMTMyMUM1MC4zNjA5IDQzLjI4MzEgNDkuOTY5OCA0My4zODY4IDQ5LjI4OSA0My40NDI0QzQ4LjU5NSA0My40OTkxIDQ3LjcwMzcgNDMuNSA0Ni40MjUgNDMuNUg0My41NzVDNDIuMjk2MyA0My41IDQxLjQwNSA0My40OTkxIDQwLjcxMSA0My40NDI0QzQwLjAzMDIgNDMuMzg2OCAzOS42MzkxIDQzLjI4MzEgMzkuMzQyOCA0My4xMzIxQzM4LjcwNzcgNDIuODA4NiAzOC4xOTE0IDQyLjI5MjMgMzcuODY3OSA0MS42NTcyQzM3LjcxNjkgNDEuMzYwOSAzNy42MTMyIDQwLjk2OTggMzcuNTU3NiA0MC4yODlaIgogICAgZmlsbD0iIzYxNjE2MSIKICAvPgo8L3N2Zz4K";
202
-
203
- var SvgArrowRightIcon = function SvgArrowRightIcon(props) {
204
- return /*#__PURE__*/React.createElement("svg", Object.assign({
205
- viewBox: "0 0 20 20"
206
- }, props), /*#__PURE__*/React.createElement("path", {
207
- fillRule: "evenodd",
208
- 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"
209
- }));
210
- };
211
- SvgArrowRightIcon.displayName = "ArrowRightIcon";
212
-
213
- var SvgCalendarIcon = function SvgCalendarIcon(props) {
214
- return /*#__PURE__*/React.createElement("svg", Object.assign({
215
- viewBox: "0 0 20 20"
216
- }, props), /*#__PURE__*/React.createElement("path", {
217
- fillRule: "evenodd",
218
- 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"
219
- }));
220
- };
221
- SvgCalendarIcon.displayName = "CalendarIcon";
222
-
223
- var SvgCheckIcon = function SvgCheckIcon(props) {
224
- return /*#__PURE__*/React.createElement("svg", Object.assign({
225
- viewBox: "0 0 20 20"
226
- }, props), /*#__PURE__*/React.createElement("path", {
227
- fillRule: "evenodd",
228
- 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"
229
- }));
230
- };
231
- SvgCheckIcon.displayName = "CheckIcon";
232
-
233
- var SvgChevronDownIcon = function SvgChevronDownIcon(props) {
234
- return /*#__PURE__*/React.createElement("svg", Object.assign({
235
- viewBox: "0 0 20 20"
236
- }, props), /*#__PURE__*/React.createElement("path", {
237
- fillRule: "evenodd",
238
- 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"
239
- }));
240
- };
241
- SvgChevronDownIcon.displayName = "ChevronDownIcon";
242
-
243
- var SvgChevronRightIcon = function SvgChevronRightIcon(props) {
244
- return /*#__PURE__*/React.createElement("svg", Object.assign({
245
- viewBox: "0 0 20 20"
246
- }, props), /*#__PURE__*/React.createElement("path", {
247
- fillRule: "evenodd",
248
- 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"
249
- }));
250
- };
251
- SvgChevronRightIcon.displayName = "ChevronRightIcon";
252
-
253
- var SvgChevronUpIcon = function SvgChevronUpIcon(props) {
254
- return /*#__PURE__*/React.createElement("svg", Object.assign({
255
- viewBox: "0 0 20 20"
256
- }, props), /*#__PURE__*/React.createElement("path", {
257
- fillRule: "evenodd",
258
- 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"
259
- }));
260
- };
261
- SvgChevronUpIcon.displayName = "ChevronUpIcon";
262
-
263
- const TRIM_DECIMAL_ZEROS_REGEX = /\.0+$/;
264
- const DEFAULT_DECIMALS = 2;
265
- const trimDecimalZeros = (number) => {
266
- return `${number}`.replace(TRIM_DECIMAL_ZEROS_REGEX, '');
267
- };
268
- const cleanDecimal = (number, decimals = DEFAULT_DECIMALS) => {
269
- return trimDecimalZeros(number.toFixed(decimals));
270
- };
271
- const semverToNum = (v) => {
272
- const [major, minor, patch] = v.split('.').map((n) => Number(n));
273
- return (major ?? 0) * 1_000_000 + (minor ?? 0) * 1_000 + (patch ?? 0);
274
- };
275
- const numberWithCommas = (x) => {
276
- return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
277
- };
278
-
279
- /**
280
- * Utility function to calculate percentage and format it.
281
- * @param part - The part value.
282
- * @param total - The total value.
283
- * @param decimals - The number of decimal places to format the percentage to.
284
- * @returns The formatted percentage as a string.
285
- */
286
- const PERCENTAGE_THRESHOLD = 0.005;
287
- const PERCENTAGE_THRESHOLD_STRING = '~0%';
288
- const calcPercentage = (part, total, decimals = DEFAULT_DECIMALS) => {
289
- if (typeof part !== 'number' || !total)
290
- return undefined;
291
- if (part === 0)
292
- return 0;
293
- const percentage = (part / total) * 100;
294
- return parseFloat(cleanDecimal(percentage, decimals));
295
- };
296
- const isLessThanThreshold = (percentage) => percentage > 0 && percentage < PERCENTAGE_THRESHOLD;
297
- const calcPercentageString = (part, total, decimals = 2) => {
298
- const percentage = calcPercentage(part, total, decimals);
299
- if (typeof percentage !== 'number')
300
- return undefined;
301
- if (isLessThanThreshold(percentage)) {
302
- return PERCENTAGE_THRESHOLD_STRING;
303
- }
304
- return `${percentage}%`;
305
- };
306
- const formatPercentage = (percentage, decimals = DEFAULT_DECIMALS) => {
307
- if (isLessThanThreshold(percentage)) {
308
- return PERCENTAGE_THRESHOLD_STRING;
309
- }
310
- return `${cleanDecimal(percentage, decimals)}%`;
311
- };
312
-
313
- function toVal(mix) {
314
- if (typeof mix === 'string') {
315
- return mix;
316
- }
317
- else if (typeof mix === 'object' && mix !== null) {
318
- return Object.keys(mix)
319
- .filter((key) => mix[key])
320
- .join(' ');
321
- }
322
- else {
323
- return false;
324
- }
325
- }
326
- function cls(...classes) {
327
- return classes.map(toVal).filter(Boolean).join(' ');
328
- }
329
-
330
- function compareValues(a, b, order = 'asc') {
331
- if (a === b)
332
- return 0;
333
- if (a === undefined || b === undefined) {
334
- if (a === undefined && b !== undefined)
335
- return order === 'asc' ? -1 : 1;
336
- if (b === undefined && a !== undefined)
337
- return order === 'asc' ? 1 : -1;
338
- return 0;
339
- }
340
- const isDate = (val) => typeof val !== 'boolean' && !isNaN(Date.parse(val));
341
- const isString = (val) => typeof val === 'string';
342
- let comparison = 0;
343
- if (isDate(a) && isDate(b)) {
344
- const dateA = a instanceof Date ? a : new Date(a);
345
- const dateB = b instanceof Date ? b : new Date(b);
346
- comparison = dateA > dateB ? 1 : -1;
347
- }
348
- else if (isString(a) && isString(b)) {
349
- comparison = a > b ? 1 : -1;
350
- }
351
- else {
352
- comparison = a > b ? 1 : -1;
353
- }
354
- return order === 'asc' ? -comparison : comparison;
355
- }
356
- function getNestedValue(obj, path) {
357
- if (typeof path === 'string') {
358
- return path
359
- .replace(/\[(\d+)\]/g, '.$1')
360
- .split('.')
361
- .reduce((acc, key) => acc?.[key], obj);
362
- }
363
- return obj[path];
364
- }
365
- function sortByCondition(array, options) {
366
- const { attr, order = 'asc', preferredValue, backupAttr, orderArrayAttr, orderArray } = options;
367
- return array.slice().sort((a, b) => {
368
- const valueA = getNestedValue(a, attr);
369
- const valueB = getNestedValue(b, attr);
370
- if (preferredValue !== undefined) {
371
- if (valueA === preferredValue && valueB !== preferredValue)
372
- return -1;
373
- if (valueB === preferredValue && valueA !== preferredValue)
374
- return 1;
375
- }
376
- if (orderArrayAttr === attr && orderArray) {
377
- const orderArrayValue = orderArray[order];
378
- return orderArrayValue.indexOf(valueA) - orderArrayValue.indexOf(valueB);
379
- }
380
- const primaryComparison = compareValues(valueA, valueB, order);
381
- if (primaryComparison !== 0)
382
- return primaryComparison;
383
- if (backupAttr)
384
- return compareValues(a[backupAttr], b[backupAttr], order);
385
- return 0;
386
- });
387
- }
388
- function sortByConditions(array, optionsArray) {
389
- return optionsArray.reduce((sortedArray, options) => {
390
- return sortByCondition(sortedArray, options);
391
- }, array.slice());
392
- }
393
-
394
- dayjs.extend(utc);
395
- dayjs.extend(timezone);
396
- dayjs.extend(quarterOfYear);
397
- let tz = 'UTC';
398
- const DEFAULT_DATE_FORMAT = 'YYYY-MM-DD HH:mm:ss';
399
- function getInitialTimezone() {
400
- return tz;
401
- }
402
- function setTz(value) {
403
- tz = value;
404
- dayjs.tz.setDefault(value);
405
- }
406
- const dayjsTz = (date) => {
407
- if (!date)
408
- return dayjs().tz(tz);
409
- return dayjs(date).tz(tz);
410
- };
411
- const convertDateToTz = (date) => {
412
- if (!date)
413
- return dayjs.tz(dayjs().format(DEFAULT_DATE_FORMAT), tz);
414
- return dayjs.tz(dayjs(date).format(DEFAULT_DATE_FORMAT), tz);
415
- };
416
- const dayjsTzToLocalTZ = (date) => {
417
- if (!date)
418
- return dayjs(dayjsTz().format(DEFAULT_DATE_FORMAT));
419
- return dayjs(dayjsTz(date).format(DEFAULT_DATE_FORMAT));
420
- };
421
- const dayjsTzToDate = (date) => {
422
- return dayjsTzToLocalTZ(date).toDate();
423
- };
424
-
425
- var AnalyticInterval;
426
- (function (AnalyticInterval) {
427
- AnalyticInterval["DAY"] = "DAY";
428
- AnalyticInterval["HOUR"] = "HOUR";
429
- AnalyticInterval["MONTH"] = "MONTH";
430
- AnalyticInterval["QUARTER"] = "QUARTER";
431
- AnalyticInterval["WEEK"] = "WEEK";
432
- AnalyticInterval["YEAR"] = "YEAR";
433
- })(AnalyticInterval || (AnalyticInterval = {}));
434
- const SECONDS_IN_MINUTE = 60;
435
- const SECONDS_IN_HOUR = SECONDS_IN_MINUTE * SECONDS_IN_MINUTE;
436
- const getTimeDurationLabel = (valueInSeconds) => {
437
- let data = valueInSeconds;
438
- if (!Number.isFinite(valueInSeconds) || valueInSeconds == null) {
439
- data = 0;
440
- }
441
- const fixedValue = cleanDecimal(data);
442
- if (data >= SECONDS_IN_HOUR) {
443
- const hours = Math.floor(data / SECONDS_IN_HOUR);
444
- const minutes = Math.floor((data % SECONDS_IN_HOUR) / SECONDS_IN_MINUTE);
445
- const seconds = Math.floor(data % SECONDS_IN_MINUTE);
446
- return `${hours}h ${minutes}m ${seconds}s`;
447
- }
448
- else if (data >= SECONDS_IN_MINUTE) {
449
- const minutes = Math.floor(data / SECONDS_IN_MINUTE);
450
- const seconds = Math.floor(data % SECONDS_IN_MINUTE);
451
- return `${minutes}m ${seconds}s`;
452
- }
453
- else {
454
- return `${fixedValue}s`;
455
- }
456
- };
457
- const getFormattedByInterval = (value, interval, options) => {
458
- if (!value)
459
- return '';
460
- const optionFormat = options?.isExpandDetail
461
- ? {
462
- formatHouse: 'MMM D, h:mm A',
463
- formatDay: 'MMM D, YYYY',
464
- formatMonth: 'MMM YYYY',
465
- formatYear: 'MMM YYYY',
466
- }
467
- : {
468
- formatHouse: 'h A',
469
- formatDay: 'MMM D',
470
- formatMonth: 'MMM YYYY',
471
- formatYear: 'YYYY',
472
- };
473
- switch (interval) {
474
- case AnalyticInterval.HOUR:
475
- return dayjsTz(value).format(optionFormat.formatHouse);
476
- case AnalyticInterval.DAY:
477
- case AnalyticInterval.WEEK:
478
- return dayjsTz(value).format(optionFormat.formatDay);
479
- case AnalyticInterval.MONTH:
480
- return dayjsTz(value).format(optionFormat.formatMonth);
481
- case AnalyticInterval.QUARTER: {
482
- const d = dayjsTz(value);
483
- return `Q${d.quarter()} ${d.format('YYYY')}`;
484
- }
485
- case AnalyticInterval.YEAR:
486
- return dayjsTz(value).format(optionFormat.formatYear);
487
- }
488
- return dayjsTz(value).format(optionFormat.formatMonth);
489
- };
490
-
491
- const GClickable = ({ children, fullWidth = false, cursor = 'pointer', onClick, onMouseEnter, onMouseLeave, }) => {
492
- return (jsx("div", { role: "button", tabIndex: 0, className: cls({
493
- 'w-full': fullWidth,
494
- 'cursor-pointer': cursor === 'pointer',
495
- 'cursor-default': cursor === 'default',
496
- 'cursor-not-allowed': cursor === 'not-allowed',
497
- }), onKeyDown: (e) => {
498
- if (e.key === 'Enter' || e.key === ' ') {
499
- e.preventDefault();
500
- onClick();
501
- }
502
- }, onClick: onClick, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, children: children }));
503
- };
504
-
505
- const GActivatorPopover = ({ onClick, active, content, textProps, boxProps: customBoxProps, disabled, icon: customIcon, }) => {
506
- const boxProps = useMemo(() => {
507
- if (disabled) {
508
- return {
509
- borderColor: 'border-disabled',
510
- background: 'bg-surface-disabled',
511
- ...customBoxProps,
512
- };
513
- }
514
- return {
515
- shadow: active ? 'button-inset' : 'button',
516
- background: active ? 'bg-fill-active' : 'bg-fill',
517
- ...customBoxProps,
518
- };
519
- }, [active, disabled, customBoxProps]);
520
- const toneClass = useMemo(() => {
521
- if (disabled) {
522
- return 'text-[var(--p-color-text-disabled)]';
523
- }
524
- return active ? 'text-[var(--p-color-text-subdued)]' : 'text-[var(--p-color-text)]';
525
- }, [active, disabled]);
526
- const textComponent = useMemo(() => {
527
- return (jsx(Text, { as: "span", variant: "bodyMd", fontWeight: "medium", tone: disabled ? 'inherit' : textProps?.tone, truncate: true, ...(textProps?.variant && { variant: textProps.variant }), children: content }));
528
- }, [content, textProps, disabled]);
529
- const handleClick = useCallback(() => {
530
- if (disabled)
531
- return;
532
- onClick();
533
- }, [disabled, onClick]);
534
- 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 })] }))] }) }) }));
535
- };
536
-
537
- const GBlockCenter = ({ height, align, inlineAlign, display, ...props }) => {
538
- const stickyStyle = useMemo(() => {
539
- if (props.position !== 'sticky')
540
- return {};
541
- const style = {
542
- position: 'sticky',
543
- };
544
- if (props.insetInlineStart)
545
- style.insetInlineStart = Number(props.insetInlineStart) * 4;
546
- if (props.insetInlineEnd)
547
- style.insetInlineEnd = Number(props.insetInlineEnd) * 4;
548
- if (props.insetBlockStart)
549
- style.insetBlockStart = Number(props.insetBlockStart) * 4;
550
- if (props.insetBlockEnd)
551
- style.insetBlockEnd = Number(props.insetBlockEnd) * 4;
552
- return style;
553
- }, [props.position, props.insetInlineStart, props.insetInlineEnd, props.insetBlockStart, props.insetBlockEnd]);
554
- return (jsx("div", { className: "Polaris-GBlockCenter", style: {
555
- ...stickyStyle,
556
- '--gp-block-center-height': height,
557
- '--gp-block-center-display': display,
558
- '--gp-block-center-align': align,
559
- '--gp-block-center-inline-align': inlineAlign,
560
- '--gp-block-center-overflow-x': props.overflowX,
561
- '--gp-block-center-overflow-y': props.overflowY,
562
- }, children: jsx(Box, { ...props }) }));
563
- };
564
-
565
- const GTooltip = ({ isEnabled = true, content, maxWidth, ...props }) => {
566
- const hasContent = isEnabled && !!content;
567
- return hasContent ? (jsx(Tooltip, { width: "wide", hoverDelay: 500, content: content, ...props, accessibilityLabel: maxWidth?.toString() })) : (props.children);
568
- };
569
-
570
- const GButton = ({ activatorWrapper, children, iconRight, inset, stopPropagation = true, onClick, themeTone = 'light', variant, ...props }) => {
571
- const Wrapper = activatorWrapper || 'div';
572
- const isNeutral = variant === 'neutral';
573
- const polarisVariant = isNeutral ? undefined : variant;
574
- const handleClick = (e) => {
575
- stopPropagation && e.stopPropagation();
576
- if (props.disabled)
577
- return;
578
- onClick?.();
579
- };
580
- const button = (jsx(GTooltip, { activatorWrapper: "tooltip-content", ...props.tooltip, children: jsx(Wrapper, { className: cls('Polaris-GButton', {
581
- 'Polaris-GButton--icon-right': iconRight,
582
- 'Polaris-GButton--dark': themeTone === 'dark',
583
- 'Polaris-GButton--neutral': isNeutral,
584
- 'cursor-default': props.disabled,
585
- 'Polaris-GButton--fullWidth': props.fullWidth,
586
- flex: inset,
587
- }), onClick: handleClick, children: jsx(Button, { variant: polarisVariant, ...props, children: children }) }) }));
588
- if (inset) {
589
- return jsx(Box, { padding: "100", children: button });
590
- }
591
- return button;
592
- };
593
-
594
- const GCheckbox = ({ ...props }) => {
595
- return props.multiple ? jsx(GCheckboxMultiple, { ...props }) : jsx(GCheckboxSingle, { ...props });
596
- };
597
- const GCheckboxMultiple = ({ options, onChange, onChangeSingleValue, emptySelected, selected, onHover, itemHovered, dependentDisabledValues, }) => {
598
- const [settingOptions, setSettingOptions] = useState([]);
599
- const handleChange = (value) => {
600
- if (onChangeSingleValue) {
601
- onChangeSingleValue(value);
602
- }
603
- const updatedOptions = settingOptions.includes(value)
604
- ? settingOptions.filter((item) => item !== value)
605
- : [...settingOptions, value];
606
- setSettingOptions(updatedOptions);
607
- onChange(updatedOptions);
608
- };
609
- const handleHover = (value) => {
610
- if (!onHover)
611
- return;
612
- onHover(value);
613
- };
614
- useEffect(() => {
615
- setSettingOptions(() => {
616
- if (selected) {
617
- return options.filter((item) => selected.includes(item.value)).map((item) => item.value);
618
- }
619
- return [];
620
- });
621
- // eslint-disable-next-line react-hooks/exhaustive-deps
622
- }, [selected]);
623
- return (jsx(BlockStack, { children: options.map((item) => {
624
- const hasForceUnchecked = dependentDisabledValues?.has(item.value);
625
- const isOnlyOneSelected = emptySelected && options.filter((opt) => opt.selected).length === 1 && emptySelected;
626
- const handleCheckboxClick = () => {
627
- if (isOnlyOneSelected)
628
- return;
629
- handleChange(item.value);
630
- };
631
- return (jsx("div", { className: cls('flex w-full items-center justify-between', {
632
- 'cursor-not-allowed': isOnlyOneSelected,
633
- 'cursor-pointer': !isOnlyOneSelected,
634
- 'bg-surface-hover rounded-lg': itemHovered === item.value,
635
- }), onClick: () => {
636
- if (isOnlyOneSelected || item.disabled)
637
- return;
638
- handleCheckboxClick();
639
- }, 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));
640
- }) }));
641
- };
642
- const GCheckboxSingle = ({ options, onChange }) => {
643
- 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))) }));
644
- };
645
-
646
- const GDiv = forwardRef(({ children, onClick, ...props }, ref) => {
647
- const onKeyDown = useCallback((e) => {
648
- if (e.key === 'Enter' || e.key === ' ') {
649
- e.preventDefault();
650
- onClick?.();
651
- }
652
- }, [onClick]);
653
- return (jsx("div", { ref: ref, ...props, role: "button", tabIndex: 0, onKeyDown: onKeyDown, onClick: onClick, children: children }));
654
- });
655
- GDiv.displayName = 'GDiv';
656
-
657
- const TRANSFORMER_REGEX = /\[(\d+)\](.*?)\[\]/g;
658
- const GI18NText = (props) => {
659
- const { children, transformers } = props;
660
- if (!transformers || Object.values(transformers).length === 0) {
661
- return jsx(Text, { ...props, children: children });
662
- }
663
- const transformContent = (text) => {
664
- const parts = [];
665
- let lastIndex = 0;
666
- text.replace(TRANSFORMER_REGEX, (match, number, childrenContent, offset) => {
667
- parts.push(text.slice(lastIndex, offset));
668
- const transformerFunction = transformers[number];
669
- if (typeof transformerFunction === 'function') {
670
- parts.push(transformerFunction(childrenContent));
671
- }
672
- else {
673
- parts.push(match);
674
- }
675
- lastIndex = offset + match.length;
676
- return match;
677
- });
678
- parts.push(text.slice(lastIndex));
679
- return parts.map((part, index) => jsx(Fragment$1, { children: part }, index));
680
- };
681
- return jsx(Text, { ...props, children: typeof children === 'string' ? transformContent(children) : children });
682
- };
683
-
684
- function GOptionList({ options, selected, onChange }) {
685
- const handleSelect = (value) => {
686
- onChange([value]);
687
- };
688
- const handleKeyDown = (event, value) => {
689
- if (event.key === 'Enter' || event.key === ' ') {
690
- event.preventDefault();
691
- handleSelect(value);
692
- }
693
- };
694
- return (jsx(Box, { padding: "150", children: jsx(BlockStack, { gap: "100", children: options.map((option) => {
695
- const isSelected = selected.includes(option.value);
696
- 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', {
697
- 'bg-[#F1F1F1]': isSelected,
698
- 'hover:bg-[#F1F1F1]': !isSelected,
699
- }), 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));
700
- }) }) }));
701
- }
702
-
703
- const GSelector = (props) => {
704
- const [popoverActive, setPopoverActive] = useState(false);
705
- const { activatorText, selected, options, emptyLabel, preferredAlignment = 'right', formatActivatorContent = (text) => text.join(', '), } = props;
706
- const togglePopoverActive = useCallback(() => setPopoverActive((prev) => !prev), []);
707
- const selectedOption = useMemo(() => {
708
- return options
709
- .filter((item) => item.active || item.id === selected)
710
- .map((item) => item.content || '')
711
- .filter((item) => !!item);
712
- }, [options, selected]);
713
- const activatorContent = useMemo(() => {
714
- if (selectedOption.length) {
715
- const selected = formatActivatorContent(selectedOption);
716
- return activatorText ? `${activatorText}: ${selected}` : selected;
717
- }
718
- if (emptyLabel) {
719
- return activatorText ? `${activatorText}: ${emptyLabel}` : emptyLabel;
720
- }
721
- return activatorText;
722
- }, [selectedOption, emptyLabel, activatorText, formatActivatorContent]);
723
- const selectorMarkup = useMemo(() => {
724
- switch (props.variant) {
725
- case 'choice':
726
- return jsx(GSelectorChoice, { ...props, setPopoverActive: togglePopoverActive });
727
- case 'action-list':
728
- return jsx(GSelectorActionList, { ...props, setPopoverActive: togglePopoverActive });
729
- }
730
- }, [props, togglePopoverActive]);
731
- 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 }));
732
- };
733
- const GSelectorChoice = ({ options, selected, onSelect, maxWidth, minWidth, clearable, setPopoverActive, }) => {
734
- const { t } = useTranslation();
735
- const items = useMemo(() => {
736
- if (!options?.length)
737
- return [];
738
- return options.map((option) => ({
739
- value: option.id,
740
- label: option.content || '',
741
- selected: false,
742
- }));
743
- }, [options]);
744
- const handleSelection = useCallback((value) => {
745
- onSelect(value);
746
- }, [onSelect]);
747
- 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: () => {
748
- handleSelection([]);
749
- setPopoverActive(false);
750
- }, variant: "plain", children: t('Clear') }) }) }))] }) }));
751
- };
752
- const GSelectorActionList = ({ options, selected, onSelect, helpText, maxWidth, minWidth, setPopoverActive, }) => {
753
- const handleSelection = useCallback((value) => {
754
- onSelect(value);
755
- setPopoverActive(false);
756
- }, [onSelect, setPopoverActive]);
757
- const items = useMemo(() => {
758
- if (!options?.length)
759
- return [];
760
- return options.map((option) => ({
761
- id: option.id,
762
- content: option.content,
763
- helpText: option.helpText,
764
- onAction: () => handleSelection(option.id),
765
- active: option.active || option.id === selected,
766
- suffix: (option.active || option.id === selected) && jsx(Icon, { source: SvgCheckIcon, tone: "success" }),
767
- }));
768
- }, [options, selected, handleSelection]);
769
- return (jsx(Box, { maxWidth: maxWidth, minWidth: minWidth, children: jsxs(BlockStack, { gap: "0", children: [jsx(ActionList, { actionRole: "menuitem", items: items }), helpText] }) }));
770
- };
771
-
772
- const GTextLink = ({ linkAction, isDisabled, disabledFocus, children }) => {
773
- if (!linkAction || isDisabled) {
774
- return jsx(Fragment, { children: children });
775
- }
776
- return (jsx("span", { className: cls('GTextLink', { 'GTextLink--disabled-focus': disabledFocus }), children: jsx(Link, { ...linkAction, children: jsx(Fragment, { children: children }) }) }));
777
- };
778
-
779
- const GSkeletonDisplayText = (props) => {
780
- const height = props.height ?? '50px';
781
- return (jsxs("div", { className: "Polaris-GSkeletonDisplayText", children: [jsx("style", { children: `.Polaris-GSkeletonDisplayText .Polaris-SkeletonDisplayText__DisplayText { height: ${height} !important; }` }), jsx(SkeletonDisplayText, { maxWidth: "100%", size: "extraLarge" })] }));
782
- };
783
-
784
- /**
785
- * Helper function to generate a variation class name.
786
- * @param name - Base name of the class.
787
- * @param value - Variation value to append.
788
- * @returns Combined class name.
789
- */
790
- function variationName(name, value) {
791
- return `${name}${value.charAt(0).toUpperCase()}${value.slice(1)}`;
792
- }
793
- const GThumbnail = ({ source, alt, size, grayscale, defaultSource = THUMB_PRODUCT_DEFAULT, width = '80', height = '80', classRemoved = false, }) => {
794
- const sizeClass = size && variationName('Polaris-Thumbnail--size', size);
795
- const filterClass = grayscale && 'Polaris-GThumbnail--filter';
796
- const className = cls('Polaris-Thumbnail', sizeClass);
797
- const thumbnail = (jsx("img", { onError: (e) => {
798
- e.currentTarget.src = defaultSource;
799
- }, alt: alt ?? 'Thumbnail', src: `${source ?? defaultSource}`, width: width, height: height, style: {
800
- '--gp-grayscale-percentage': grayscale || '100%',
801
- }, className: cls('Polaris-GThumbnail', filterClass) }));
802
- if (classRemoved)
803
- return thumbnail;
804
- return jsx("span", { className: className, children: thumbnail });
805
- };
806
-
807
- const SIZE_CLASS = {
808
- default: 'w-[210px]',
809
- wide: 'w-[320px]',
810
- large: 'w-[328px]',
811
- };
812
- const ALIGNMENT_MAP = {
813
- start: 'flex justify-start',
814
- center: 'flex justify-center',
815
- end: 'flex justify-end',
816
- };
817
- const GTooltipCard = forwardRef((props, ref) => {
818
- const { tooltip, wrapper = 'div', activatorProps, isHideBorder, alignment, delay = 500, textDecoration = 'none', popoverRef, preferredAlignment = 'left', showArrow = false, } = props;
819
- const { width = 'default' } = tooltip ?? {};
820
- const [isMouseEnter, setIsMouseEnter] = useState(false);
821
- const TooltipCardWrapper = wrapper;
822
- const sizeClass = SIZE_CLASS[width];
823
- const timeoutRef = useRef(null);
824
- const handleMouseEnter = () => {
825
- timeoutRef.current = setTimeout(() => {
826
- setIsMouseEnter(true);
827
- }, delay);
828
- };
829
- const handleMouseLeave = () => {
830
- if (timeoutRef.current) {
831
- clearTimeout(timeoutRef.current);
832
- timeoutRef.current = null;
833
- }
834
- setIsMouseEnter(false);
835
- };
836
- useImperativeHandle(ref, () => ({ onClose: handleMouseLeave }));
837
- return (jsx(TooltipCardWrapper, { className: cls('GTooltipCard cursor-pointer', alignment && ALIGNMENT_MAP[alignment], {
838
- 'GTooltipCard--text-underline': textDecoration === 'underline',
839
- }), 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 }))] }) }) })) }) }));
840
- });
841
- GTooltipCard.displayName = 'GTooltipCard';
842
-
843
- const GViewBySelector = ({ activatorText, selected, options, minWidth, maxWidth, preferredAlignment = 'right', onSelect, }) => {
844
- const [popoverActive, setPopoverActive] = useState(false);
845
- const [itemHover, setItemHover] = useState(null);
846
- const togglePopoverActive = () => setPopoverActive((prev) => !prev);
847
- const selectedOption = useMemo(() => {
848
- return options.find((item) => item.id === selected);
849
- }, [options, selected]);
850
- const activatorContent = useMemo(() => {
851
- if (selectedOption) {
852
- const content = selectedOption.title ?? selectedOption.content;
853
- return activatorText ? `${activatorText}: ${content}` : content;
854
- }
855
- return activatorText;
856
- }, [selectedOption, activatorText]);
857
- const handleSelect = (value) => {
858
- onSelect(value);
859
- setPopoverActive(false);
860
- };
861
- 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) => {
862
- const isSelected = option.id === selected;
863
- const isHover = itemHover === option.id;
864
- const borderColor = isSelected ? 'input-border' : isHover ? 'border-hover' : 'transparent';
865
- 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));
866
- }) }) }) }));
867
- };
868
-
869
- const ChoiceHelpText = ({ item }) => {
870
- return (jsxs(Text, { as: "p", variant: "bodyMd", children: [item.description, item.inlineAction && (jsx(Link, { monochrome: true, onClick: () => {
871
- if (item.inlineAction?.onAction) {
872
- item.inlineAction?.onAction();
873
- }
874
- else {
875
- window.open(item.inlineAction?.url, item.inlineAction?.target ?? '_blank');
876
- }
877
- }, children: item.inlineAction?.content }))] }));
878
- };
879
-
880
- const GChartSkeleton = () => {
881
- return jsx(GSkeletonDisplayText, { height: "188px" });
882
- };
883
-
884
- const useCurrencyRatesStore = create((set) => ({
885
- currencyRates: null,
886
- setCurrencyRates: (rates) => set({ currencyRates: rates }),
887
- }));
888
-
889
- const SHOPIFY_CURRENCIES_URL = 'https://cdn.shopify.com/s/javascripts/currencies.js';
890
- const parseCurrencyRates = (scriptText) => {
891
- const rates = {};
892
- const match = /var Currency=\{rates:\{(.*?)\}\};/s.exec(scriptText);
893
- const ratesStr = match?.[1];
894
- if (!ratesStr)
895
- return rates;
896
- const ratePattern = /([A-Z]+):\s*([\d.e+-]+),/g;
897
- let m;
898
- while ((m = ratePattern.exec(ratesStr)) !== null) {
899
- const [, code, value] = m;
900
- if (code && value)
901
- rates[code] = parseFloat(value);
902
- }
903
- return rates;
904
- };
905
- const fetchCurrencyRates = async () => {
906
- const res = await fetch(SHOPIFY_CURRENCIES_URL);
907
- if (!res.ok)
908
- throw new Error('Failed to fetch currency rates');
909
- const text = await res.text();
910
- return parseCurrencyRates(text);
911
- };
912
- const useFetchCurrencyRates = () => {
913
- const setCurrencyRates = useCurrencyRatesStore((state) => state.setCurrencyRates);
914
- const { data } = useQuery({
915
- queryKey: ['sdk-currency-rates'],
916
- queryFn: fetchCurrencyRates,
917
- staleTime: 1000 * 60 * 60, // 1 hour — rates don't change often
918
- });
919
- useEffect(() => {
920
- if (data)
921
- setCurrencyRates(data);
922
- }, [data, setCurrencyRates]);
923
- };
924
-
925
- const getPriceByCurrency = (price, currency = DEFAULT_CURRENCY_ANALYTIC, options) => {
926
- if (typeof price === 'string')
927
- return price;
928
- if (typeof price !== 'number')
929
- return;
930
- // Support legacy 3rd arg as locale string
931
- const opts = typeof options === 'string' ? { locale: options } : options;
932
- const locale = opts?.locale ?? 'en-US';
933
- if (price >= 1_000_000_000) {
934
- return `${new Intl.NumberFormat(locale, {
935
- style: 'currency',
936
- currency,
937
- minimumFractionDigits: 2,
938
- maximumFractionDigits: 2,
939
- }).format(price / 1_000_000_000)}B`;
940
- }
941
- if (price >= 1_000_000) {
942
- return `${new Intl.NumberFormat(locale, {
943
- style: 'currency',
944
- currency,
945
- minimumFractionDigits: 2,
946
- maximumFractionDigits: 2,
947
- }).format(price / 1_000_000)}M`;
948
- }
949
- if (opts?.compact && Math.abs(price) >= 1_000) {
950
- return `${new Intl.NumberFormat(locale, {
951
- style: 'currency',
952
- currency,
953
- minimumFractionDigits: 1,
954
- maximumFractionDigits: 1,
955
- }).format(price / 1_000)}K`;
956
- }
957
- return new Intl.NumberFormat(locale, {
958
- style: 'currency',
959
- currency,
960
- }).format(price);
961
- };
962
-
963
- const ConvertMoneyContext = createContext({
964
- getTextPrice: (price) => {
965
- if (typeof price === 'string')
966
- return price;
967
- return `${price ?? 0}`;
968
- },
969
- });
970
- const convertAmount = (amount, from, to, rates) => {
971
- if (from === to || !rates[from] || !rates[to])
972
- return amount;
973
- const converted = (amount * rates[from]) / rates[to];
974
- return converted ? Number(converted.toFixed(2)) : amount;
975
- };
976
- const ConvertMoneyProvider = ({ children, currency, locale = 'en-US' }) => {
977
- useFetchCurrencyRates();
978
- const currencyRates = useCurrencyRatesStore((state) => state.currencyRates);
979
- const getTextPrice = useCallback((price, _hasCurrency, options) => {
980
- if (typeof price === 'string')
981
- return price;
982
- if (typeof price !== 'number')
983
- return '0';
984
- if (!currency)
985
- return price.toString();
986
- const converted = currencyRates
987
- ? convertAmount(price, DEFAULT_CURRENCY_ANALYTIC, currency, currencyRates)
988
- : price;
989
- return trimDecimalZeros(getPriceByCurrency(converted, currency, { locale, compact: options?.compact }) ?? '0');
990
- }, [currency, locale, currencyRates]);
991
- const value = useMemo(() => ({ getTextPrice }), [getTextPrice]);
992
- return jsx(ConvertMoneyContext.Provider, { value: value, children: children });
993
- };
994
- const useConvertMoneyContext = () => useContext(ConvertMoneyContext);
995
-
996
- const LINE_SERIES_COLORS = {
997
- comparison: SERIES_COLORS.comparison,
998
- single: SERIES_COLORS.current,
999
- all: [...SERIES_COLORS.all],
1000
- };
1001
- const MetricChartProvider = ({ children, minHeight = CHART_MIN_HEIGHT, seriesColors = LINE_SERIES_COLORS, }) => {
1002
- return (jsxs(Fragment, { children: [jsx("link", { rel: "stylesheet", href: chartStyle }), jsx(PolarisVizProvider, { themes: {
1003
- Light: {
1004
- chartContainer: {
1005
- minHeight,
1006
- },
1007
- grid: {
1008
- horizontalOverflow: true,
1009
- verticalOverflow: true,
1010
- horizontalMargin: 0,
1011
- },
1012
- seriesColors,
1013
- },
1014
- }, children: children })] }));
1015
- };
1016
-
1017
126
  const NONE_VALUE = 'None';
1018
- const PLACEHOLDER_VALUE = '-';
127
+ const PLACEHOLDER_VALUE$1 = '-';
1019
128
 
1020
129
  const TOTALS_SUFFIX = '___totals';
1021
130
  const COMPARE_PREFIX = 'comparison___';
@@ -1049,12 +158,42 @@ var EAnalyticColumnKey;
1049
158
  EAnalyticColumnKey["TRAFFIC_SOURCE_ITEMS"] = "traffic_source_items";
1050
159
  })(EAnalyticColumnKey || (EAnalyticColumnKey = {}));
1051
160
 
161
+ var EAnalyticMode;
162
+ (function (EAnalyticMode) {
163
+ EAnalyticMode["ALL_SESSION"] = "ALL_SESSION";
164
+ EAnalyticMode["FIRST_SESSION"] = "FIRST_SESSION";
165
+ EAnalyticMode["PAGE_ONLY"] = "PAGE_ONLY";
166
+ })(EAnalyticMode || (EAnalyticMode = {}));
167
+
1052
168
  var EAnalyticSource;
1053
169
  (function (EAnalyticSource) {
1054
170
  EAnalyticSource["SESSIONS"] = "sessions";
1055
171
  EAnalyticSource["SALES"] = "sales";
1056
172
  })(EAnalyticSource || (EAnalyticSource = {}));
1057
173
 
174
+ var EVisitorType;
175
+ (function (EVisitorType) {
176
+ EVisitorType["NEW"] = "new";
177
+ EVisitorType["RETURNING"] = "returning";
178
+ })(EVisitorType || (EVisitorType = {}));
179
+ var EDeviceType;
180
+ (function (EDeviceType) {
181
+ EDeviceType["DESKTOP"] = "desktop";
182
+ EDeviceType["MOBILE"] = "mobile";
183
+ EDeviceType["TABLET"] = "tablet";
184
+ })(EDeviceType || (EDeviceType = {}));
185
+ var ETrafficSourceType;
186
+ (function (ETrafficSourceType) {
187
+ ETrafficSourceType["DIRECT"] = "direct";
188
+ ETrafficSourceType["EMAIL"] = "email";
189
+ ETrafficSourceType["REFERRAL"] = "referral";
190
+ ETrafficSourceType["ORGANIC_SOCIAL"] = "organic-social";
191
+ ETrafficSourceType["ORGANIC_SEARCH"] = "organic-search";
192
+ ETrafficSourceType["PAID_SOCIAL"] = "paid-social";
193
+ ETrafficSourceType["PAID_SEARCH"] = "paid-search";
194
+ ETrafficSourceType["SMS"] = "sms";
195
+ })(ETrafficSourceType || (ETrafficSourceType = {}));
196
+
1058
197
  var EComparisonOperator;
1059
198
  (function (EComparisonOperator) {
1060
199
  EComparisonOperator["EQ"] = "=";
@@ -1161,6 +300,175 @@ var ETimeDimension;
1161
300
  [ERowReaderMode.COMPARISON_TOTALS]: { prefix: COMPARE_PREFIX, suffix: COMPARE_TOTALS_SUFFIX },
1162
301
  });
1163
302
 
303
+ EGroupOperator.OR;
304
+
305
+ [
306
+ {
307
+ operator: EOperatorField.DEVICE_OPERATOR,
308
+ singleField: EFilterField.DEVICE,
309
+ multiField: EFilterField.DEVICES,
310
+ fieldName: EFilterField.DEVICE,
311
+ },
312
+ {
313
+ operator: EOperatorField.VISITOR_OPERATOR,
314
+ singleField: EFilterField.VISITOR,
315
+ multiField: EFilterField.VISITORS,
316
+ fieldName: EFilterField.VISITOR,
317
+ },
318
+ {
319
+ operator: EOperatorField.TRAFFIC_SOURCE_OPERATOR,
320
+ singleField: EFilterField.TRAFFIC_SOURCE,
321
+ multiField: EFilterField.TRAFFIC_SOURCES,
322
+ fieldName: EFilterField.TRAFFIC_SOURCE,
323
+ },
324
+ {
325
+ operator: EOperatorField.VERSION_OPERATOR,
326
+ singleField: EFilterField.VERSION,
327
+ multiField: EFilterField.VERSIONS,
328
+ fieldName: EFilterField.VERSION,
329
+ },
330
+ {
331
+ operator: EOperatorField.PAGE_OPERATOR,
332
+ singleField: EFilterField.SINGLE_PAGE,
333
+ multiField: EFilterField.LIST_PAGE,
334
+ fieldName: EFilterField.SINGLE_PAGE,
335
+ },
336
+ {
337
+ operator: EOperatorField.CAMPAIGN_ITEM_OPERATOR,
338
+ singleField: EFilterField.GROUP_CAMPAIGN_ITEM,
339
+ multiField: EFilterField.GROUP_CAMPAIGN_ITEMS,
340
+ condition: EFilterField.GROUP_CAMPAIGN,
341
+ fieldName: EFilterField.SINGLE_CAMPAIGN,
342
+ },
343
+ {
344
+ operatorVal: OPERATOR_IS,
345
+ singleField: EFilterField.SINGLE_CAMPAIGN,
346
+ multiField: EFilterField.GROUP_CAMPAIGN,
347
+ },
348
+ ];
349
+
350
+ dayjs.extend(utc);
351
+ dayjs.extend(timezone);
352
+ dayjs.extend(quarterOfYear);
353
+ let tz = 'UTC';
354
+ const dayjsTz = (date) => {
355
+ if (!date)
356
+ return dayjs().tz(tz);
357
+ return dayjs(date).tz(tz);
358
+ };
359
+
360
+ const TRIM_DECIMAL_ZEROS_REGEX = /\.0+$/;
361
+ const DEFAULT_DECIMALS = 2;
362
+ const trimDecimalZeros = (number) => {
363
+ return `${number}`.replace(TRIM_DECIMAL_ZEROS_REGEX, '');
364
+ };
365
+ const cleanDecimal = (number, decimals = DEFAULT_DECIMALS) => {
366
+ return trimDecimalZeros(number.toFixed(decimals));
367
+ };
368
+
369
+ /**
370
+ * Utility function to calculate percentage and format it.
371
+ * @param part - The part value.
372
+ * @param total - The total value.
373
+ * @param decimals - The number of decimal places to format the percentage to.
374
+ * @returns The formatted percentage as a string.
375
+ */
376
+ const PERCENTAGE_THRESHOLD = 0.005;
377
+ const PERCENTAGE_THRESHOLD_STRING = '~0%';
378
+ const calcPercentage = (part, total, decimals = DEFAULT_DECIMALS) => {
379
+ if (typeof part !== 'number' || !total)
380
+ return undefined;
381
+ if (part === 0)
382
+ return 0;
383
+ const percentage = (part / total) * 100;
384
+ return parseFloat(cleanDecimal(percentage, decimals));
385
+ };
386
+ const isLessThanThreshold = (percentage) => percentage > 0 && percentage < PERCENTAGE_THRESHOLD;
387
+ const calcPercentageString = (part, total, decimals = 2) => {
388
+ const percentage = calcPercentage(part, total, decimals);
389
+ if (typeof percentage !== 'number')
390
+ return undefined;
391
+ if (isLessThanThreshold(percentage)) {
392
+ return PERCENTAGE_THRESHOLD_STRING;
393
+ }
394
+ return `${percentage}%`;
395
+ };
396
+ const formatPercentage = (percentage, decimals = DEFAULT_DECIMALS) => {
397
+ if (isLessThanThreshold(percentage)) {
398
+ return PERCENTAGE_THRESHOLD_STRING;
399
+ }
400
+ return `${cleanDecimal(percentage, decimals)}%`;
401
+ };
402
+
403
+ var AnalyticInterval;
404
+ (function (AnalyticInterval) {
405
+ AnalyticInterval["DAY"] = "DAY";
406
+ AnalyticInterval["HOUR"] = "HOUR";
407
+ AnalyticInterval["MONTH"] = "MONTH";
408
+ AnalyticInterval["QUARTER"] = "QUARTER";
409
+ AnalyticInterval["WEEK"] = "WEEK";
410
+ AnalyticInterval["YEAR"] = "YEAR";
411
+ })(AnalyticInterval || (AnalyticInterval = {}));
412
+ function numberWithCommas(x) {
413
+ return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
414
+ }
415
+ const SECONDS_IN_MINUTE = 60;
416
+ const SECONDS_IN_HOUR = SECONDS_IN_MINUTE * SECONDS_IN_MINUTE;
417
+ const getTimeDurationLabel = (valueInSeconds) => {
418
+ let data = valueInSeconds;
419
+ if (!Number.isFinite(valueInSeconds) || valueInSeconds == null) {
420
+ data = 0;
421
+ }
422
+ const fixedValue = cleanDecimal(data);
423
+ if (data >= SECONDS_IN_HOUR) {
424
+ const hours = Math.floor(data / SECONDS_IN_HOUR);
425
+ const minutes = Math.floor((data % SECONDS_IN_HOUR) / SECONDS_IN_MINUTE);
426
+ const seconds = Math.floor(data % SECONDS_IN_MINUTE);
427
+ return `${hours}h ${minutes}m ${seconds}s`;
428
+ }
429
+ else if (data >= SECONDS_IN_MINUTE) {
430
+ const minutes = Math.floor(data / SECONDS_IN_MINUTE);
431
+ const seconds = Math.floor(data % SECONDS_IN_MINUTE);
432
+ return `${minutes}m ${seconds}s`;
433
+ }
434
+ else {
435
+ return `${fixedValue}s`;
436
+ }
437
+ };
438
+ const getFormattedByInterval = (value, interval, options) => {
439
+ if (!value)
440
+ return '';
441
+ const optionFormat = options?.isExpandDetail
442
+ ? {
443
+ formatHouse: 'MMM D, h:mm A',
444
+ formatDay: 'MMM D, YYYY',
445
+ formatMonth: 'MMM YYYY',
446
+ formatYear: 'MMM YYYY',
447
+ }
448
+ : {
449
+ formatHouse: 'h A',
450
+ formatDay: 'MMM D',
451
+ formatMonth: 'MMM YYYY',
452
+ formatYear: 'YYYY',
453
+ };
454
+ switch (interval) {
455
+ case AnalyticInterval.HOUR:
456
+ return dayjsTz(value).format(optionFormat.formatHouse);
457
+ case AnalyticInterval.DAY:
458
+ case AnalyticInterval.WEEK:
459
+ return dayjsTz(value).format(optionFormat.formatDay);
460
+ case AnalyticInterval.MONTH:
461
+ return dayjsTz(value).format(optionFormat.formatMonth);
462
+ case AnalyticInterval.QUARTER: {
463
+ const d = dayjsTz(value);
464
+ return `Q${d.quarter()} ${d.format('YYYY')}`;
465
+ }
466
+ case AnalyticInterval.YEAR:
467
+ return dayjsTz(value).format(optionFormat.formatYear);
468
+ }
469
+ return dayjsTz(value).format(optionFormat.formatMonth);
470
+ };
471
+
1164
472
  const formatAnalyticDate = (dateString) => {
1165
473
  if (!dateString)
1166
474
  return 'None';
@@ -1240,62 +548,235 @@ const formatAnalyticData = ({ value, formatter, getTextPrice, name, }) => {
1240
548
  }
1241
549
  };
1242
550
 
1243
- const SESSION_KEY = 'sessions';
1244
- const hasMetricData = (metric) => {
1245
- const sessions = metric?.[SESSION_KEY];
1246
- return typeof sessions === 'number' && sessions > 0;
551
+ const SESSION_KEY = 'sessions';
552
+ const hasMetricData = (metric) => {
553
+ const sessions = metric?.[SESSION_KEY];
554
+ return typeof sessions === 'number' && sessions > 0;
555
+ };
556
+
557
+ const parseRawJson = (raw) => {
558
+ if (!raw)
559
+ return undefined;
560
+ return typeof raw === 'string' ? JSON.parse(raw) : raw;
561
+ };
562
+ const parseJsonArray = (raw) => {
563
+ try {
564
+ const parsed = parseRawJson(raw);
565
+ if (!Array.isArray(parsed))
566
+ return undefined;
567
+ return parsed;
568
+ }
569
+ catch {
570
+ return undefined;
571
+ }
572
+ };
573
+ const parseBreakdownItems = (raw) => parseJsonArray(raw)?.map((item) => ({ ...item, total: Number(item.total) }));
574
+
575
+ const readNumeric = (metric, key) => {
576
+ const raw = metric?.[key];
577
+ return typeof raw === 'number' ? raw : 0;
578
+ };
579
+
580
+ const useAnalyticData = (getTextPrice) => {
581
+ const formatData = ({ value, formatter, name }) => {
582
+ return formatAnalyticData({ value, formatter, getTextPrice, name });
583
+ };
584
+ const computeMetric = ({ metric, previousMetric, metricKey, formatter, }) => {
585
+ if (!hasMetricData(metric))
586
+ return { value: 0, change: PLACEHOLDER_VALUE$1 };
587
+ const currentValue = readNumeric(metric, metricKey);
588
+ const previousValue = readNumeric(previousMetric, metricKey);
589
+ const value = formatData({ value: currentValue, formatter, name: metricKey });
590
+ if (currentValue === 0 && previousValue !== 0)
591
+ return { value, change: -100 };
592
+ if (previousValue === 0)
593
+ return { value, change: PLACEHOLDER_VALUE$1 };
594
+ const change = ((currentValue - previousValue) / previousValue) * 100;
595
+ return { value, change };
596
+ };
597
+ return { formatData, computeMetric };
598
+ };
599
+
600
+ var GPaginationDirection;
601
+ (function (GPaginationDirection) {
602
+ GPaginationDirection["NEXT"] = "NEXT";
603
+ GPaginationDirection["PREV"] = "PREV";
604
+ })(GPaginationDirection || (GPaginationDirection = {}));
605
+
606
+ const TARGET_VISITOR = [
607
+ { value: EVisitorType.NEW, label: 'New' },
608
+ { value: EVisitorType.RETURNING, label: 'Returning' },
609
+ ];
610
+ const TARGET_DEVICES = [
611
+ { value: EDeviceType.DESKTOP, label: 'Desktop' },
612
+ { value: EDeviceType.TABLET, label: 'Tablet' },
613
+ { value: EDeviceType.MOBILE, label: 'Mobile' },
614
+ ];
615
+ const TARGET_CHANNEL = [
616
+ { value: ETrafficSourceType.DIRECT, label: 'Direct' },
617
+ { value: ETrafficSourceType.EMAIL, label: 'Email' },
618
+ { value: ETrafficSourceType.REFERRAL, label: 'Referral' },
619
+ { value: ETrafficSourceType.ORGANIC_SOCIAL, label: 'Organic social' },
620
+ { value: ETrafficSourceType.ORGANIC_SEARCH, label: 'Organic search' },
621
+ { value: ETrafficSourceType.PAID_SOCIAL, label: 'Paid social' },
622
+ { value: ETrafficSourceType.PAID_SEARCH, label: 'Paid search' },
623
+ { value: ETrafficSourceType.SMS, label: 'SMS' },
624
+ ];
625
+
626
+ const CAMPAIGN_BACKGROUND_MAIN = {
627
+ ORIGIN: '#2C7DFF',
628
+ VARIANT: '#F34A70',
629
+ };
630
+
631
+ const DEFAULT_CURRENT_PERIOD_LABEL = 'Current';
632
+ const DEFAULT_PREVIOUS_PERIOD_LABEL = 'Previous';
633
+ const CHART_MIN_HEIGHT = 228;
634
+ const SERIES_COLORS = {
635
+ current: 'rgba(64, 176, 230, 1)',
636
+ comparison: 'rgba(161, 202, 231, 1)',
637
+ all: ['#2C7DFF', '#F34A70'],
638
+ };
639
+ const TREND_TONE = {
640
+ POSITIVE: '#007F5F',
641
+ NEUTRAL: '#4A4A4A',
642
+ };
643
+ const PLACEHOLDER_VALUE = '-';
644
+
645
+ var THUMB_PRODUCT_DEFAULT = "data:image/svg+xml;base64,PHN2ZwogIHdpZHRoPSI5MCIKICBoZWlnaHQ9IjcyIgogIHZpZXdCb3g9IjAgMCA5MCA3MiIKICBmaWxsPSJub25lIgogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKPgogIDxwYXRoCiAgICBkPSJNNDguNzUgMzQuNUM0OS45OTI2IDM0LjUgNTEgMzMuNDkyNiA1MSAzMi4yNUM1MSAzMS4wMDc0IDQ5Ljk5MjYgMzAgNDguNzUgMzBDNDcuNTA3NCAzMCA0Ni41IDMxLjAwNzQgNDYuNSAzMi4yNUM0Ni41IDMzLjQ5MjYgNDcuNTA3NCAzNC41IDQ4Ljc1IDM0LjVaIgogICAgZmlsbD0iIzYxNjE2MSIKICAvPgogIDxwYXRoCiAgICBmaWxsUnVsZT0iZXZlbm9kZCIKICAgIGNsaXBSdWxlPSJldmVub2RkIgogICAgZD0iTTQzLjUyNjggMjYuMjVINDYuNDczMkM0Ny42OTI0IDI2LjI1IDQ4LjY3NTggMjYuMjUgNDkuNDcyMiAyNi4zMTVDNTAuMjkyMiAyNi4zODIgNTEuMDEyNCAyNi41MjM2IDUxLjY3ODcgMjYuODYzMUM1Mi43MzcxIDI3LjQwMjQgNTMuNTk3NiAyOC4yNjI5IDU0LjEzNjkgMjkuMzIxM0M1NC40NzY0IDI5Ljk4NzYgNTQuNjE4IDMwLjcwNzggNTQuNjg1IDMxLjUyNzhDNTQuNzUgMzIuMzI0MiA1NC43NSAzMy4zMDc2IDU0Ljc1IDM0LjUyNjhWMzcuNDczMkM1NC43NSAzOC42OTI0IDU0Ljc1IDM5LjY3NTggNTQuNjg1IDQwLjQ3MjJDNTQuNjE4IDQxLjI5MjIgNTQuNDc2NCA0Mi4wMTI0IDU0LjEzNjkgNDIuNjc4N0M1My41OTc2IDQzLjczNzEgNTIuNzM3MSA0NC41OTc2IDUxLjY3ODcgNDUuMTM2OUM1MS4wMTI0IDQ1LjQ3NjQgNTAuMjkyMiA0NS42MTggNDkuNDcyMiA0NS42ODVDNDguNjc1OCA0NS43NSA0Ny42OTI0IDQ1Ljc1IDQ2LjQ3MzIgNDUuNzVINDMuNTI2OEM0Mi4zMDc2IDQ1Ljc1IDQxLjMyNDIgNDUuNzUgNDAuNTI3OCA0NS42ODVDMzkuNzA3OCA0NS42MTggMzguOTg3NiA0NS40NzY0IDM4LjMyMTMgNDUuMTM2OUMzNy4yNjI5IDQ0LjU5NzYgMzYuNDAyNCA0My43MzcxIDM1Ljg2MzEgNDIuNjc4N0MzNS41MjM2IDQyLjAxMjQgMzUuMzgyIDQxLjI5MjIgMzUuMzE1IDQwLjQ3MjJDMzUuMjUgMzkuNjc1OCAzNS4yNSAzOC42OTI0IDM1LjI1IDM3LjQ3MzJWMzQuNTI2OEMzNS4yNSAzMy4zMDc2IDM1LjI1IDMyLjMyNDIgMzUuMzE1IDMxLjUyNzhDMzUuMzgyIDMwLjcwNzggMzUuNTIzNiAyOS45ODc2IDM1Ljg2MzEgMjkuMzIxM0MzNi40MDI0IDI4LjI2MjkgMzcuMjYyOSAyNy40MDI0IDM4LjMyMTMgMjYuODYzMUMzOC45ODc2IDI2LjUyMzYgMzkuNzA3OCAyNi4zODIgNDAuNTI3OCAyNi4zMTVDNDEuMzI0MiAyNi4yNSA0Mi4zMDc2IDI2LjI1IDQzLjUyNjggMjYuMjVaTTQwLjcxMSAyOC41NTc2QzQwLjAzMDIgMjguNjEzMiAzOS42MzkxIDI4LjcxNjkgMzkuMzQyOCAyOC44Njc5QzM4LjcwNzcgMjkuMTkxNCAzOC4xOTE0IDI5LjcwNzcgMzcuODY3OSAzMC4zNDI4QzM3LjcxNjkgMzAuNjM5MSAzNy42MTMyIDMxLjAzMDIgMzcuNTU3NiAzMS43MTFDMzcuNTAwOSAzMi40MDUgMzcuNSAzMy4yOTYzIDM3LjUgMzQuNTc1VjM2LjcxNzdMMzguNTg0MiAzNS40MTY3QzM5LjU3MjQgMzQuMjMwOSA0MS4zNjU1IDM0LjE0OTYgNDIuNDU2OSAzNS4yNDFMNDYuNSAzOS4yODQxTDQ4LjI2OTQgMzcuNTE0NkM0OS4zNzU3IDM2LjQwODMgNTEuMTk4IDM2LjUwOTMgNTIuMTc1NCAzNy43MzA5TDUyLjQ5OTUgMzguMTM2MUM1Mi41IDM3LjkxMzEgNTIuNSAzNy42NzY1IDUyLjUgMzcuNDI1VjM0LjU3NUM1Mi41IDMzLjI5NjMgNTIuNDk5MSAzMi40MDUgNTIuNDQyNCAzMS43MTFDNTIuMzg2OCAzMS4wMzAyIDUyLjI4MzEgMzAuNjM5MSA1Mi4xMzIxIDMwLjM0MjhDNTEuODA4NiAyOS43MDc3IDUxLjI5MjMgMjkuMTkxNCA1MC42NTcyIDI4Ljg2NzlDNTAuMzYwOSAyOC43MTY5IDQ5Ljk2OTggMjguNjEzMiA0OS4yODkgMjguNTU3NkM0OC41OTUgMjguNTAwOSA0Ny43MDM3IDI4LjUgNDYuNDI1IDI4LjVINDMuNTc1QzQyLjI5NjMgMjguNSA0MS40MDUgMjguNTAwOSA0MC43MTEgMjguNTU3NlpNMzcuNTU3NiA0MC4yODlDMzcuNTU0MyA0MC4yNDkyIDM3LjU1MTMgNDAuMjA4OCAzNy41NDg0IDQwLjE2NzhDMzcuNTcxMSA0MC4xNDQ4IDM3LjU5MzEgNDAuMTIwNiAzNy42MTQyIDQwLjA5NTNMNDAuMzEyNyAzNi44NTcxQzQwLjQ1MzkgMzYuNjg3NyA0MC43MSAzNi42NzYxIDQwLjg2NTkgMzYuODMyTDQ1LjcwNDUgNDEuNjcwNkM0Ni4xNDM4IDQyLjEwOTkgNDYuODU2MSA0Mi4xMDk5IDQ3LjI5NTUgNDEuNjcwNkw0OS44NjA0IDM5LjEwNTZDNTAuMDE4NSAzOC45NDc2IDUwLjI3ODggMzguOTYyIDUwLjQxODQgMzkuMTM2NUw1Mi4yMzc3IDQxLjQxMDdDNTIuMjA1NiA0MS41MDEgNTIuMTcwNCA0MS41ODIyIDUyLjEzMjEgNDEuNjU3MkM1MS44MDg2IDQyLjI5MjMgNTEuMjkyMyA0Mi44MDg2IDUwLjY1NzIgNDMuMTMyMUM1MC4zNjA5IDQzLjI4MzEgNDkuOTY5OCA0My4zODY4IDQ5LjI4OSA0My40NDI0QzQ4LjU5NSA0My40OTkxIDQ3LjcwMzcgNDMuNSA0Ni40MjUgNDMuNUg0My41NzVDNDIuMjk2MyA0My41IDQxLjQwNSA0My40OTkxIDQwLjcxMSA0My40NDI0QzQwLjAzMDIgNDMuMzg2OCAzOS42MzkxIDQzLjI4MzEgMzkuMzQyOCA0My4xMzIxQzM4LjcwNzcgNDIuODA4NiAzOC4xOTE0IDQyLjI5MjMgMzcuODY3OSA0MS42NTcyQzM3LjcxNjkgNDEuMzYwOSAzNy42MTMyIDQwLjk2OTggMzcuNTU3NiA0MC4yODlaIgogICAgZmlsbD0iIzYxNjE2MSIKICAvPgo8L3N2Zz4K";
646
+
647
+ const GBlockCenter = ({ height, align, inlineAlign, display, ...props }) => {
648
+ const stickyStyle = useMemo(() => {
649
+ if (props.position !== 'sticky')
650
+ return {};
651
+ const style = {
652
+ position: 'sticky',
653
+ };
654
+ if (props.insetInlineStart)
655
+ style.insetInlineStart = Number(props.insetInlineStart) * 4;
656
+ if (props.insetInlineEnd)
657
+ style.insetInlineEnd = Number(props.insetInlineEnd) * 4;
658
+ if (props.insetBlockStart)
659
+ style.insetBlockStart = Number(props.insetBlockStart) * 4;
660
+ if (props.insetBlockEnd)
661
+ style.insetBlockEnd = Number(props.insetBlockEnd) * 4;
662
+ return style;
663
+ }, [props.position, props.insetInlineStart, props.insetInlineEnd, props.insetBlockStart, props.insetBlockEnd]);
664
+ return (jsx("div", { className: "Polaris-GBlockCenter", style: {
665
+ ...stickyStyle,
666
+ '--gp-block-center-height': height,
667
+ '--gp-block-center-display': display,
668
+ '--gp-block-center-align': align,
669
+ '--gp-block-center-inline-align': inlineAlign,
670
+ '--gp-block-center-overflow-x': props.overflowX,
671
+ '--gp-block-center-overflow-y': props.overflowY,
672
+ }, children: jsx(Box, { ...props }) }));
1247
673
  };
1248
674
 
1249
- const parseRawJson = (raw) => {
1250
- if (!raw)
1251
- return undefined;
1252
- return typeof raw === 'string' ? JSON.parse(raw) : raw;
675
+ const GSkeletonDisplayText = (props) => {
676
+ const height = props.height ?? '50px';
677
+ return (jsxs("div", { className: "Polaris-GSkeletonDisplayText", children: [jsx("style", { children: `.Polaris-GSkeletonDisplayText .Polaris-SkeletonDisplayText__DisplayText { height: ${height} !important; }` }), jsx(SkeletonDisplayText, { maxWidth: "100%", size: "extraLarge" })] }));
1253
678
  };
1254
- const parseJsonArray = (raw) => {
1255
- try {
1256
- const parsed = parseRawJson(raw);
1257
- if (!Array.isArray(parsed))
1258
- return undefined;
1259
- return parsed;
679
+
680
+ function toVal(mix) {
681
+ if (typeof mix === 'string') {
682
+ return mix;
1260
683
  }
1261
- catch {
1262
- return undefined;
684
+ else if (typeof mix === 'object' && mix !== null) {
685
+ return Object.keys(mix)
686
+ .filter((key) => mix[key])
687
+ .join(' ');
1263
688
  }
1264
- };
1265
- const parseBreakdownItems = (raw) => parseJsonArray(raw)?.map((item) => ({ ...item, total: Number(item.total) }));
689
+ else {
690
+ return false;
691
+ }
692
+ }
693
+ function cls(...classes) {
694
+ return classes.map(toVal).filter(Boolean).join(' ');
695
+ }
1266
696
 
1267
- const readNumeric = (metric, key) => {
1268
- const raw = metric?.[key];
1269
- return typeof raw === 'number' ? raw : 0;
697
+ /**
698
+ * Helper function to generate a variation class name.
699
+ * @param name - Base name of the class.
700
+ * @param value - Variation value to append.
701
+ * @returns Combined class name.
702
+ */
703
+ function variationName(name, value) {
704
+ return `${name}${value.charAt(0).toUpperCase()}${value.slice(1)}`;
705
+ }
706
+ const GThumbnail = ({ source, alt, size, grayscale, defaultSource = THUMB_PRODUCT_DEFAULT, width = '80', height = '80', classRemoved = false, }) => {
707
+ const sizeClass = size && variationName('Polaris-Thumbnail--size', size);
708
+ const filterClass = grayscale && 'Polaris-GThumbnail--filter';
709
+ const className = cls('Polaris-Thumbnail', sizeClass);
710
+ const thumbnail = (jsx("img", { onError: (e) => {
711
+ e.currentTarget.src = defaultSource;
712
+ }, alt: alt ?? 'Thumbnail', src: `${source ?? defaultSource}`, width: width, height: height, style: {
713
+ '--gp-grayscale-percentage': grayscale || '100%',
714
+ }, className: cls('Polaris-GThumbnail', filterClass) }));
715
+ if (classRemoved)
716
+ return thumbnail;
717
+ return jsx("span", { className: className, children: thumbnail });
1270
718
  };
1271
719
 
1272
- const useAnalyticData = ({ getTextPrice: getTextPriceParam, } = {}) => {
1273
- const { getTextPrice: getTextPriceCtx } = useConvertMoneyContext();
1274
- const getTextPrice = getTextPriceParam ?? getTextPriceCtx;
1275
- const formatData = ({ value, formatter, name }) => {
1276
- return formatAnalyticData({ value, formatter, getTextPrice, name });
720
+ const SIZE_CLASS = {
721
+ default: 'w-[210px]',
722
+ wide: 'w-[320px]',
723
+ large: 'w-[328px]',
724
+ };
725
+ const ALIGNMENT_MAP = {
726
+ start: 'flex justify-start',
727
+ center: 'flex justify-center',
728
+ end: 'flex justify-end',
729
+ };
730
+ const GTooltipCard = forwardRef((props, ref) => {
731
+ const { tooltip, wrapper = 'div', activatorProps, isHideBorder, alignment, delay = 500, textDecoration = 'none', popoverRef, preferredAlignment = 'left', showArrow = false, } = props;
732
+ const { width = 'default' } = tooltip ?? {};
733
+ const [isMouseEnter, setIsMouseEnter] = useState(false);
734
+ const TooltipCardWrapper = wrapper;
735
+ const sizeClass = SIZE_CLASS[width];
736
+ const timeoutRef = useRef(null);
737
+ const handleMouseEnter = () => {
738
+ timeoutRef.current = setTimeout(() => {
739
+ setIsMouseEnter(true);
740
+ }, delay);
1277
741
  };
1278
- const computeMetric = ({ metric, previousMetric, metricKey, formatter, }) => {
1279
- if (!hasMetricData(metric))
1280
- return { value: 0, change: PLACEHOLDER_VALUE };
1281
- const currentValue = readNumeric(metric, metricKey);
1282
- const previousValue = readNumeric(previousMetric, metricKey);
1283
- const value = formatData({ value: currentValue, formatter, name: metricKey });
1284
- if (currentValue === 0 && previousValue !== 0)
1285
- return { value, change: -100 };
1286
- if (previousValue === 0)
1287
- return { value, change: PLACEHOLDER_VALUE };
1288
- const change = ((currentValue - previousValue) / previousValue) * 100;
1289
- return { value, change };
742
+ const handleMouseLeave = () => {
743
+ if (timeoutRef.current) {
744
+ clearTimeout(timeoutRef.current);
745
+ timeoutRef.current = null;
746
+ }
747
+ setIsMouseEnter(false);
1290
748
  };
1291
- return { formatData, computeMetric };
749
+ useImperativeHandle(ref, () => ({ onClose: handleMouseLeave }));
750
+ return (jsx(TooltipCardWrapper, { className: cls('GTooltipCard cursor-pointer', alignment && ALIGNMENT_MAP[alignment], {
751
+ 'GTooltipCard--text-underline': textDecoration === 'underline',
752
+ }), 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 }))] }) }) })) }) }));
753
+ });
754
+ GTooltipCard.displayName = 'GTooltipCard';
755
+
756
+ const GChartSkeleton = () => {
757
+ return jsx(GSkeletonDisplayText, { height: "188px" });
1292
758
  };
1293
759
 
1294
- var GPaginationDirection;
1295
- (function (GPaginationDirection) {
1296
- GPaginationDirection["NEXT"] = "NEXT";
1297
- GPaginationDirection["PREV"] = "PREV";
1298
- })(GPaginationDirection || (GPaginationDirection = {}));
760
+ const LINE_SERIES_COLORS = {
761
+ comparison: SERIES_COLORS.comparison,
762
+ single: SERIES_COLORS.current,
763
+ all: [...SERIES_COLORS.all],
764
+ };
765
+ const MetricChartProvider = ({ children, minHeight = CHART_MIN_HEIGHT, seriesColors = LINE_SERIES_COLORS, }) => {
766
+ return (jsx(PolarisVizProvider, { themes: {
767
+ Light: {
768
+ chartContainer: {
769
+ minHeight,
770
+ },
771
+ grid: {
772
+ horizontalOverflow: true,
773
+ verticalOverflow: true,
774
+ horizontalMargin: 0,
775
+ },
776
+ seriesColors,
777
+ },
778
+ }, children: children }));
779
+ };
1299
780
 
1300
781
  const useFormatLineChartData = ({ metricKey, columnTypes }) => {
1301
782
  const { formatData } = useAnalyticData();
@@ -1311,20 +792,6 @@ const useFormatLineChartData = ({ metricKey, columnTypes }) => {
1311
792
  return { formatValue, yAxisOptions };
1312
793
  };
1313
794
 
1314
- /**
1315
- * Returns a stateful value, and a set of memoized functions to toggle it,
1316
- * set it to true and set it to false
1317
- */
1318
- function useToggle(initialState) {
1319
- const [value, setState] = useState(initialState);
1320
- return {
1321
- value,
1322
- toggle: useCallback(() => setState((state) => !state), []),
1323
- setTrue: useCallback(() => setState(true), []),
1324
- setFalse: useCallback(() => setState(false), []),
1325
- };
1326
- }
1327
-
1328
795
  const useWindowSize = () => {
1329
796
  const [windowSize, setWindowSize] = useState(() => ({
1330
797
  width: typeof window !== 'undefined' ? window.innerWidth : 0,
@@ -1413,7 +880,7 @@ const MetricChartTooltip = ({ data, formatValue }) => {
1413
880
  const formatPercent = () => {
1414
881
  const value = currentData.trend?.value;
1415
882
  if (!value)
1416
- return PLACEHOLDER_VALUE$1;
883
+ return PLACEHOLDER_VALUE;
1417
884
  const valueNumber = Number(value.replace(/[%~]/g, ''));
1418
885
  if (currentData.trend?.trend === 'negative') {
1419
886
  return valueNumber * -1;
@@ -1434,90 +901,53 @@ const MetricDonutChartSkeleton = () => {
1434
901
  return (jsx(Card, { children: jsxs(BlockStack, { gap: "400", children: [jsx(MetricInfoSkeleton, { isShowOneLine: true }), jsx(GChartSkeleton, {})] }) }));
1435
902
  };
1436
903
 
904
+ var SvgChevronRightIcon = function SvgChevronRightIcon(props) {
905
+ return /*#__PURE__*/React.createElement("svg", Object.assign({
906
+ viewBox: "0 0 20 20"
907
+ }, props), /*#__PURE__*/React.createElement("path", {
908
+ fillRule: "evenodd",
909
+ 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"
910
+ }));
911
+ };
912
+ SvgChevronRightIcon.displayName = "ChevronRightIcon";
913
+
1437
914
  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 })] }) }));
1438
915
 
1439
916
  const MetricInfoBlock = ({ item, isHovered, isLoading, hideComparison, titleVariant = 'headingMd', titleFontWeight, onClickTitle, }) => {
1440
917
  const { key, title, totalValue } = item;
1441
918
  const tooltip = ANALYTICS_METRIC_TOOLTIP[key];
1442
- if (isLoading)
1443
- return jsx(MetricInfoSkeleton, {});
1444
- return (jsxs(BlockStack, { gap: "200", children: [jsx("div", { className: "hover:cursor-pointer hover:text-[--p-color-text-link-hover]", onClick: (e) => {
1445
- e?.stopPropagation();
1446
- onClickTitle?.(key);
1447
- }, 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 })] }));
1448
- };
1449
-
1450
- const MetricChartTab = ({ item, isActive, isLoading, hideComparison, onSelect, onClickTitle, }) => {
1451
- const [isHovered, setIsHovered] = useState(false);
1452
- const isHighlighted = isActive || isHovered;
1453
- 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 }) }) }));
1454
- };
1455
-
1456
- const GSelectableMetricChartCard = ({ metricInfo, dataChart, defaultActiveTab, isLoading, isEmptyMetricData, hideComparison, currentPeriodLabel = DEFAULT_CURRENT_PERIOD_LABEL, previousPeriodLabel = DEFAULT_PREVIOUS_PERIOD_LABEL, columnTypes, }) => {
1457
- const [activeTab, setActiveTab] = useState(defaultActiveTab);
1458
- const lineChartData = useMemo(() => {
1459
- const chartData = activeTab ? dataChart[activeTab] : undefined;
1460
- if (!chartData)
1461
- return [];
1462
- const currentSeries = { name: currentPeriodLabel, data: chartData.current };
1463
- if (hideComparison)
1464
- return [currentSeries];
1465
- return [currentSeries, { name: previousPeriodLabel, data: chartData.previous, isComparison: true }];
1466
- }, [activeTab, dataChart, hideComparison, currentPeriodLabel, previousPeriodLabel]);
1467
- return (jsxs(Card, { children: [jsx("div", { style: {
1468
- display: 'grid',
1469
- gridTemplateColumns: `repeat(${metricInfo.length}, 1fr)`,
1470
- gap: '16px',
1471
- marginBottom: '16px',
1472
- }, 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 })] }));
1473
- };
1474
-
1475
- EGroupOperator.OR;
1476
-
1477
- [
1478
- {
1479
- operator: EOperatorField.DEVICE_OPERATOR,
1480
- singleField: EFilterField.DEVICE,
1481
- multiField: EFilterField.DEVICES,
1482
- fieldName: EFilterField.DEVICE,
1483
- },
1484
- {
1485
- operator: EOperatorField.VISITOR_OPERATOR,
1486
- singleField: EFilterField.VISITOR,
1487
- multiField: EFilterField.VISITORS,
1488
- fieldName: EFilterField.VISITOR,
1489
- },
1490
- {
1491
- operator: EOperatorField.TRAFFIC_SOURCE_OPERATOR,
1492
- singleField: EFilterField.TRAFFIC_SOURCE,
1493
- multiField: EFilterField.TRAFFIC_SOURCES,
1494
- fieldName: EFilterField.TRAFFIC_SOURCE,
1495
- },
1496
- {
1497
- operator: EOperatorField.VERSION_OPERATOR,
1498
- singleField: EFilterField.VERSION,
1499
- multiField: EFilterField.VERSIONS,
1500
- fieldName: EFilterField.VERSION,
1501
- },
1502
- {
1503
- operator: EOperatorField.PAGE_OPERATOR,
1504
- singleField: EFilterField.SINGLE_PAGE,
1505
- multiField: EFilterField.LIST_PAGE,
1506
- fieldName: EFilterField.SINGLE_PAGE,
1507
- },
1508
- {
1509
- operator: EOperatorField.CAMPAIGN_ITEM_OPERATOR,
1510
- singleField: EFilterField.GROUP_CAMPAIGN_ITEM,
1511
- multiField: EFilterField.GROUP_CAMPAIGN_ITEMS,
1512
- condition: EFilterField.GROUP_CAMPAIGN,
1513
- fieldName: EFilterField.SINGLE_CAMPAIGN,
1514
- },
1515
- {
1516
- operatorVal: OPERATOR_IS,
1517
- singleField: EFilterField.SINGLE_CAMPAIGN,
1518
- multiField: EFilterField.GROUP_CAMPAIGN,
1519
- },
1520
- ];
919
+ if (isLoading)
920
+ return jsx(MetricInfoSkeleton, {});
921
+ return (jsxs(BlockStack, { gap: "200", children: [jsx("div", { className: "hover:cursor-pointer hover:text-[--p-color-text-link-hover]", onClick: (e) => {
922
+ e?.stopPropagation();
923
+ onClickTitle?.(key);
924
+ }, 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 })] }));
925
+ };
926
+
927
+ const MetricChartTab = ({ item, isActive, isLoading, hideComparison, onSelect, onClickTitle, }) => {
928
+ const [isHovered, setIsHovered] = useState(false);
929
+ const isHighlighted = isActive || isHovered;
930
+ 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 }) }) }));
931
+ };
932
+
933
+ const GSelectableMetricChartCard = ({ metricInfo, dataChart, defaultActiveTab, isLoading, isEmptyMetricData, hideComparison, currentPeriodLabel = DEFAULT_CURRENT_PERIOD_LABEL, previousPeriodLabel = DEFAULT_PREVIOUS_PERIOD_LABEL, columnTypes, }) => {
934
+ const [activeTab, setActiveTab] = useState(defaultActiveTab);
935
+ const lineChartData = useMemo(() => {
936
+ const chartData = activeTab ? dataChart[activeTab] : undefined;
937
+ if (!chartData)
938
+ return [];
939
+ const currentSeries = { name: currentPeriodLabel, data: chartData.current };
940
+ if (hideComparison)
941
+ return [currentSeries];
942
+ return [currentSeries, { name: previousPeriodLabel, data: chartData.previous, isComparison: true }];
943
+ }, [activeTab, dataChart, hideComparison, currentPeriodLabel, previousPeriodLabel]);
944
+ return (jsxs(Card, { children: [jsx("div", { style: {
945
+ display: 'grid',
946
+ gridTemplateColumns: `repeat(${metricInfo.length}, 1fr)`,
947
+ gap: '16px',
948
+ marginBottom: '16px',
949
+ }, 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 })] }));
950
+ };
1521
951
 
1522
952
  const calculatePercentageChange = (current, previous) => {
1523
953
  if (current === 0 && previous === 0) {
@@ -1588,1100 +1018,4 @@ const SingleMetricChartCard = ({ metricInfo, lineChartData, isLoading, hideCompa
1588
1018
  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 })] }) }) }));
1589
1019
  };
1590
1020
 
1591
- var IMAGE_FIRST_SESSION = "data:image/png;base64,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";
1592
-
1593
- var IMAGE_ALL_SESSION = "data:image/png;base64,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";
1594
-
1595
- const VIEW_BY_OPTIONS = [
1596
- {
1597
- id: EAnalyticMode.ALL_SESSION,
1598
- content: 'All sessions',
1599
- helpText: 'Count metrics for all sessions where this page shows up anywhere in the journey: before, during, or after other pages.',
1600
- icon: IMAGE_ALL_SESSION,
1601
- },
1602
- {
1603
- id: EAnalyticMode.FIRST_SESSION,
1604
- content: 'Entry session only',
1605
- helpText: 'Count metrics for sessions only where this page was the very first page visited, then track how they moved through the funnel.',
1606
- icon: IMAGE_FIRST_SESSION,
1607
- },
1608
- ];
1609
- const AnalyticModeSelector = ({ activatorText = 'View by', value, onChange }) => {
1610
- const options = useMemo(() => {
1611
- return VIEW_BY_OPTIONS.map((option) => ({
1612
- ...option,
1613
- }));
1614
- }, []);
1615
- const onSelectMode = (value) => {
1616
- onChange(value);
1617
- };
1618
- return (jsx(GViewBySelector, { activatorText: activatorText, options: options, selected: value, onSelect: onSelectMode, maxWidth: "650px" }));
1619
- };
1620
-
1621
- const EXCHANGE_RATE_HELP_URL = 'https://help.shopify.com/en/manual/international/pricing/exchange-rates#auto-convert';
1622
- const CurrencySelector = ({ currencies, selected, preferredAlignment = 'left', activatorText, onSelect, }) => {
1623
- const { t } = useTranslation();
1624
- const onSelectRef = useRef(onSelect);
1625
- const handleSelection = useCallback((value) => {
1626
- onSelectRef.current?.(value);
1627
- }, []);
1628
- const actionItems = useMemo(() => {
1629
- if (!currencies)
1630
- return [];
1631
- const formattedCurrencies = currencies.map((currency) => ({
1632
- content: currency,
1633
- id: currency,
1634
- }));
1635
- const hasCurrencyDefault = formattedCurrencies.some((item) => item.id === DEFAULT_CURRENCY_ANALYTIC);
1636
- if (!hasCurrencyDefault) {
1637
- formattedCurrencies.push({
1638
- content: DEFAULT_CURRENCY_ANALYTIC,
1639
- id: DEFAULT_CURRENCY_ANALYTIC,
1640
- });
1641
- }
1642
- return sortByConditions(formattedCurrencies, [
1643
- { attr: 'content', order: 'asc', preferredValue: DEFAULT_CURRENCY_ANALYTIC },
1644
- ]);
1645
- }, [currencies]);
1646
- const actionListItems = useMemo(() => {
1647
- return actionItems.map((option) => ({
1648
- id: option.id,
1649
- content: option.content,
1650
- onAction: () => handleSelection(option.id),
1651
- active: option.id === selected,
1652
- suffix: option.id === selected && jsx(Icon, { source: SvgCheckIcon, tone: "success" }),
1653
- helpText: option.id === DEFAULT_CURRENCY_ANALYTIC && (jsx(Text, { as: "p", fontWeight: "semibold", children: t('Default') })),
1654
- }));
1655
- }, [actionItems, selected, handleSelection, t]);
1656
- const isHidden = useMemo(() => {
1657
- if (!actionItems?.length)
1658
- return true;
1659
- return actionItems.length === 1 && actionItems[0]?.id === DEFAULT_CURRENCY_ANALYTIC;
1660
- }, [actionItems]);
1661
- useEffect(() => {
1662
- onSelectRef.current = onSelect;
1663
- });
1664
- if (isHidden)
1665
- return null;
1666
- return (jsx(GSelector, { options: actionListItems, selected: selected, variant: "action-list",
1667
- // value originates from our CurrencyCode option ids, so the widen-to-string round trip is safe
1668
- 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: {
1669
- 1: (text) => (jsx(GTextLink, { linkAction: {
1670
- url: EXCHANGE_RATE_HELP_URL,
1671
- target: '_blank',
1672
- }, children: text }, text + 'text-link')),
1673
- }, children: t("This will follow Shopify's current exchange rate. [1]Read more[]") }) }) }));
1674
- };
1675
-
1676
- var MainDateTimePickerAlias;
1677
- (function (MainDateTimePickerAlias) {
1678
- MainDateTimePickerAlias["TODAY"] = "today";
1679
- MainDateTimePickerAlias["YESTERDAY"] = "yesterday";
1680
- MainDateTimePickerAlias["LAST_7_DAYS"] = "last7days";
1681
- MainDateTimePickerAlias["LAST_30_DAYS"] = "last30days";
1682
- MainDateTimePickerAlias["LAST_90_DAYS"] = "last90days";
1683
- MainDateTimePickerAlias["LAST_365_DAYS"] = "last365days";
1684
- MainDateTimePickerAlias["LAST_MONTH"] = "lastMonth";
1685
- MainDateTimePickerAlias["LAST_12_MONTHS"] = "last12Months";
1686
- MainDateTimePickerAlias["LAST_YEAR"] = "lastYear";
1687
- })(MainDateTimePickerAlias || (MainDateTimePickerAlias = {}));
1688
- function getDateTimeFilterMapping() {
1689
- const mappings = {
1690
- [MainDateTimePickerAlias.TODAY]: {
1691
- title: 'Today',
1692
- alias: MainDateTimePickerAlias.TODAY,
1693
- getDateRange: getToday,
1694
- },
1695
- [MainDateTimePickerAlias.YESTERDAY]: {
1696
- title: 'Yesterday',
1697
- alias: MainDateTimePickerAlias.YESTERDAY,
1698
- getDateRange: getYesterday,
1699
- },
1700
- [MainDateTimePickerAlias.LAST_7_DAYS]: {
1701
- title: 'Last 7 days',
1702
- alias: MainDateTimePickerAlias.LAST_7_DAYS,
1703
- getDateRange: getLast7Days,
1704
- },
1705
- [MainDateTimePickerAlias.LAST_30_DAYS]: {
1706
- title: 'Last 30 days',
1707
- alias: MainDateTimePickerAlias.LAST_30_DAYS,
1708
- getDateRange: getLast30Days,
1709
- },
1710
- [MainDateTimePickerAlias.LAST_90_DAYS]: {
1711
- title: 'Last 90 days',
1712
- alias: MainDateTimePickerAlias.LAST_90_DAYS,
1713
- getDateRange: getLast90Days,
1714
- },
1715
- [MainDateTimePickerAlias.LAST_365_DAYS]: {
1716
- title: 'Last 365 days',
1717
- alias: MainDateTimePickerAlias.LAST_365_DAYS,
1718
- getDateRange: getLast365Days,
1719
- },
1720
- [MainDateTimePickerAlias.LAST_MONTH]: {
1721
- title: 'Last month',
1722
- alias: MainDateTimePickerAlias.LAST_MONTH,
1723
- getDateRange: getLastMonth,
1724
- },
1725
- [MainDateTimePickerAlias.LAST_12_MONTHS]: {
1726
- title: 'Last 12 months',
1727
- alias: MainDateTimePickerAlias.LAST_12_MONTHS,
1728
- getDateRange: getLast12Months,
1729
- },
1730
- [MainDateTimePickerAlias.LAST_YEAR]: {
1731
- title: 'Last year',
1732
- alias: MainDateTimePickerAlias.LAST_YEAR,
1733
- getDateRange: getLastYear,
1734
- },
1735
- };
1736
- return mappings;
1737
- }
1738
- function getDateTimeFilterByAlias(alias) {
1739
- const mappings = getDateTimeFilterMapping();
1740
- return mappings[alias];
1741
- }
1742
-
1743
- const DATE_FORMAT = {
1744
- YMD: 'YYYY-MM-DD', // 2025-01-01
1745
- MONTH_YEAR: 'MMM YYYY', // Jan 2025
1746
- FULL: 'MMMM D, YYYY', // January 1, 2025
1747
- FULL_WITH_TIME: 'MMMM D, YYYY [at] h:mm A', // January 1, 2025 at 12:00 AM
1748
- SHORT: 'MMM DD, YYYY', // Jan 01, 2025
1749
- SHORT_NO_PAD: 'MMM D, YYYY', // Jan 1, 2025
1750
- SHORT_WITH_TIME: 'MMM D, YYYY [at] h:mm A', // Jan 1, 2025 at 12:00 AM
1751
- MONTH_DAY: 'MMM D', // Jan 1
1752
- DAY_YEAR: 'D, YYYY', // 1, 2025
1753
- TIME: 'h:mm A', // 12:00 AM
1754
- MONTH_DAY_WITH_TIME: 'MMM D [at] h:mm A', // Jan 1 at 12:00 AM
1755
- YEAR: 'YYYY', // 2025
1756
- };
1757
-
1758
- function parseYearMonthDayDateString(input) {
1759
- // Date-only strings (e.g. "1970-01-01") are treated as UTC, not local time
1760
- // when using new Date()
1761
- // We need to split year, month, day to pass into new Date() separately
1762
- // to get a localized Date
1763
- return dayjs(input).valueOf();
1764
- }
1765
- const VALID_YYYY_MM_DD_DATE_REGEX = /^\d{4}-\d{1,2}-\d{1,2}/;
1766
- function isDate(date) {
1767
- return !isNaN(new Date(date).getDate());
1768
- }
1769
- function isValidYearMonthDayDateString(date) {
1770
- return VALID_YYYY_MM_DD_DATE_REGEX.test(date) && isDate(date);
1771
- }
1772
- function isValidDate(date) {
1773
- return date.length === 10 && isValidYearMonthDayDateString(date);
1774
- }
1775
- function formatDate(timestamp, type) {
1776
- const date = convertDateToTz(timestamp);
1777
- if (type === 'YMD') {
1778
- return date.format(DATE_FORMAT.YMD);
1779
- }
1780
- if (type === 'MY') {
1781
- return date.format(DATE_FORMAT.MONTH_YEAR);
1782
- }
1783
- if (type === 'FULL') {
1784
- return date.format(DATE_FORMAT.FULL);
1785
- }
1786
- if (type === 'FULL_WITH_TIME') {
1787
- return date.format(DATE_FORMAT.FULL_WITH_TIME);
1788
- }
1789
- return date.format(DATE_FORMAT.SHORT);
1790
- }
1791
- function formatTime(timestamp) {
1792
- const date = convertDateToTz(timestamp);
1793
- return date.format(DATE_FORMAT.TIME);
1794
- }
1795
- function isSameDayTimestamp(since, until) {
1796
- const sinceDate = convertDateToTz(since);
1797
- const untilDate = convertDateToTz(until);
1798
- return sinceDate.isSame(untilDate, 'day');
1799
- }
1800
- function formatTimeRange(data) {
1801
- const { since, until, format = DATE_FORMAT.TIME, showNow = false } = data;
1802
- const sinceDate = convertDateToTz(since);
1803
- const untilDate = convertDateToTz(until);
1804
- return `${sinceDate.format(format)} - ${showNow ? 'Now' : untilDate.format(format)}`;
1805
- }
1806
- function formatDateTimeRange(data) {
1807
- const { since, until, isShowNow } = data;
1808
- const sinceDate = convertDateToTz(since);
1809
- const untilDate = convertDateToTz(until);
1810
- const isToday = sinceDate.isSame(dayjsTz(), 'day');
1811
- const startTime = sinceDate.format(DATE_FORMAT.TIME);
1812
- const endTime = untilDate.format(DATE_FORMAT.TIME);
1813
- if (isToday) {
1814
- const formatEndTime = isShowNow ? 'Now' : endTime;
1815
- return `Today at ${startTime} - ${formatEndTime}`;
1816
- }
1817
- if (isShowNow) {
1818
- return `${sinceDate.format(DATE_FORMAT.SHORT_WITH_TIME)} - Now`;
1819
- }
1820
- if (sinceDate.isSame(untilDate, 'day')) {
1821
- return `${sinceDate.format(DATE_FORMAT.SHORT_WITH_TIME)} - ${endTime}`;
1822
- }
1823
- if (sinceDate.isSame(untilDate, 'day')) {
1824
- const time = formatTimeRange({ since, until });
1825
- return `${sinceDate.format(DATE_FORMAT.SHORT)} (${time})`;
1826
- }
1827
- if (sinceDate.isSame(untilDate, 'year')) {
1828
- return `${sinceDate.format(DATE_FORMAT.MONTH_DAY_WITH_TIME)} - ${untilDate.format(DATE_FORMAT.MONTH_DAY_WITH_TIME)}, ${untilDate.format(DATE_FORMAT.YEAR)}`;
1829
- }
1830
- return `${sinceDate.format(DATE_FORMAT.SHORT_WITH_TIME)} - ${untilDate.format(DATE_FORMAT.SHORT_WITH_TIME)}`;
1831
- }
1832
- const formatDayjs = (date, isEndDay = false, formatTemplate) => {
1833
- // const isUTC = date.isUTC?.() ?? false;
1834
- // if (isUTC) return date.format();
1835
- if (isEndDay && isMidnight(date)) {
1836
- return date.endOf('day').format(formatTemplate);
1837
- }
1838
- return date.format(formatTemplate);
1839
- };
1840
- const getEndOfDayBy = (value, formatTemplate) => {
1841
- if (!value) {
1842
- return formatDayjs(dayjsTz().endOf('day'), false, formatTemplate);
1843
- }
1844
- return formatDayjs(dayjsTz(value).endOf('day'), false, formatTemplate);
1845
- };
1846
- const isMidnight = (date) => {
1847
- return date.hour() === 0 && date.minute() === 0;
1848
- };
1849
- const formatMs = (ms) => {
1850
- const totalSeconds = Math.floor(ms / 1000);
1851
- const hours = Math.floor(totalSeconds / 3600);
1852
- const minutes = Math.floor((totalSeconds % 3600) / 60);
1853
- const seconds = totalSeconds % 60;
1854
- return [hours, minutes, seconds].map((v) => String(v).padStart(2, '0')).join(':');
1855
- };
1856
-
1857
- function getDateRangeTitle(since, until) {
1858
- const sinceDate = convertDateToTz(since);
1859
- const untilDate = convertDateToTz(until);
1860
- if (sinceDate.isSame(untilDate, 'day')) {
1861
- return sinceDate.format(DATE_FORMAT.SHORT);
1862
- }
1863
- if (sinceDate.isSame(untilDate, 'month') && sinceDate.isSame(untilDate, 'year')) {
1864
- return `${sinceDate.format(DATE_FORMAT.MONTH_DAY)} - ${untilDate.format(DATE_FORMAT.DAY_YEAR)}`;
1865
- }
1866
- if (sinceDate.isSame(untilDate, 'year')) {
1867
- return `${sinceDate.format(DATE_FORMAT.MONTH_DAY)} - ${untilDate.format(DATE_FORMAT.SHORT_NO_PAD)}`;
1868
- }
1869
- return `${sinceDate.format(DATE_FORMAT.SHORT_NO_PAD)} - ${untilDate.format(DATE_FORMAT.SHORT_NO_PAD)}`;
1870
- }
1871
- /**
1872
- * Resolves a { title, alias } pair from a since/until date range.
1873
- * Matches against known presets (today, last 7 days, …); falls back to
1874
- * a formatted custom range with alias "custom".
1875
- */
1876
- function getDateTimeFilterBase(since, until) {
1877
- const now = dayjsTz();
1878
- const sinceDate = convertDateToTz(since);
1879
- const untilDate = convertDateToTz(until);
1880
- const mappings = getDateTimeFilterMapping();
1881
- for (const mapping of Object.values(mappings)) {
1882
- const range = mapping.getDateRange(now);
1883
- const expectedSince = convertDateToTz(range.since);
1884
- const expectedUntil = convertDateToTz(range.until);
1885
- const isSameSince = sinceDate.isSame(expectedSince, 'day');
1886
- const isSameUntil = untilDate.isSame(expectedUntil, 'day');
1887
- if (isSameSince && isSameUntil) {
1888
- return { title: mapping.title, alias: mapping.alias };
1889
- }
1890
- }
1891
- return {
1892
- title: getDateRangeTitle(since, until),
1893
- alias: 'custom',
1894
- };
1895
- }
1896
- function getVersionDateRangeTitle(data) {
1897
- const { since, until, isShowNow } = data;
1898
- const sinceDate = convertDateToTz(since);
1899
- const isToday = sinceDate.isSame(dayjsTz(), 'day');
1900
- if (isToday)
1901
- return getDateTimeFilterByAlias(MainDateTimePickerAlias.TODAY).title;
1902
- if (isShowNow)
1903
- return `${sinceDate.format(DATE_FORMAT.SHORT_NO_PAD)} - Now`;
1904
- return getDateRangeTitle(since, until);
1905
- }
1906
- const getVersionDateDescription = ({ since, until, isShowNow }) => {
1907
- const isSameDay = isSameDayTimestamp(since, until);
1908
- if (!isSameDay)
1909
- return undefined;
1910
- return formatTimeRange({ since, until, showNow: isShowNow });
1911
- };
1912
-
1913
- const convertToDateTimeFilters = (versions) => {
1914
- const dataVersions = [...versions].sort((a, b) => semverToNum(b.version) - semverToNum(a.version));
1915
- return dataVersions
1916
- .map((item) => {
1917
- if (!item.startedAt)
1918
- return false;
1919
- const isCurrentVersion = !item.completedAt;
1920
- const since = dayjsTzToLocalTZ(item.startedAt).valueOf();
1921
- const until = isCurrentVersion
1922
- ? dayjsTzToLocalTZ(getEndOfDayBy()).valueOf()
1923
- : dayjsTzToLocalTZ(item.completedAt).valueOf();
1924
- const title = getVersionDateRangeTitle({ since, until, isShowNow: isCurrentVersion });
1925
- const description = getVersionDateDescription({ since, until, isShowNow: isCurrentVersion });
1926
- return {
1927
- title,
1928
- alias: `${item.version}`,
1929
- since,
1930
- until,
1931
- isVersion: true,
1932
- isCurrentVersion,
1933
- description,
1934
- versionId: item.id,
1935
- };
1936
- })
1937
- .filter(Boolean);
1938
- };
1939
-
1940
- const getNoComparison = () => {
1941
- return {
1942
- since: 0,
1943
- until: 0,
1944
- };
1945
- };
1946
- const getPreviousPeriod = (value) => {
1947
- const { since, until, alias } = value;
1948
- const sinceDate = dayjs(since);
1949
- const untilDate = dayjs(until);
1950
- if (alias === MainDateTimePickerAlias.LAST_MONTH) {
1951
- return getLastMonth(sinceDate);
1952
- }
1953
- if (alias === MainDateTimePickerAlias.LAST_12_MONTHS) {
1954
- return getLast12Months(sinceDate);
1955
- }
1956
- if (alias === MainDateTimePickerAlias.LAST_YEAR) {
1957
- return getLastYear(sinceDate);
1958
- }
1959
- const duration = untilDate.diff(sinceDate, 'day') + 1;
1960
- const previousSince = sinceDate.subtract(duration, 'day');
1961
- const previousUntil = untilDate.subtract(duration, 'day');
1962
- return {
1963
- since: previousSince.valueOf(),
1964
- until: previousUntil.valueOf(),
1965
- };
1966
- };
1967
- const createPreviousRange = (subtractAmount, subtractUnit) => (value) => {
1968
- const { since, until } = value;
1969
- const sinceDate = dayjs(since);
1970
- const untilDate = dayjs(until);
1971
- const duration = untilDate.diff(sinceDate, 'day');
1972
- const previousSince = sinceDate.subtract(subtractAmount, subtractUnit);
1973
- const previousUntil = previousSince.add(duration, 'day');
1974
- return {
1975
- since: previousSince.valueOf(),
1976
- until: previousUntil.valueOf(),
1977
- };
1978
- };
1979
- const getPreviousWeek = createPreviousRange(7, 'day');
1980
- const getPreviousQuarter = createPreviousRange(3, 'month');
1981
- const getPreviousMonth = createPreviousRange(1, 'month');
1982
- const getPreviousYear = createPreviousRange(1, 'year');
1983
- const createLastDaysRange = (subtractAmount) => (date) => {
1984
- return {
1985
- since: date.subtract(subtractAmount, 'day').valueOf(),
1986
- until: date.valueOf(),
1987
- };
1988
- };
1989
- const getToday = (currentDate) => {
1990
- return {
1991
- since: currentDate.valueOf(),
1992
- until: currentDate.valueOf(),
1993
- };
1994
- };
1995
- const getYesterday = (date) => {
1996
- return {
1997
- since: date.subtract(1, 'day').valueOf(),
1998
- until: date.subtract(1, 'day').valueOf(),
1999
- };
2000
- };
2001
- const getLast7Days = createLastDaysRange(6);
2002
- const getLast30Days = createLastDaysRange(29);
2003
- const getLast90Days = createLastDaysRange(89);
2004
- const getLast365Days = createLastDaysRange(364);
2005
- function getLastMonth(date) {
2006
- return {
2007
- since: date.subtract(1, 'month').startOf('month').valueOf(),
2008
- until: date.subtract(1, 'month').endOf('month').valueOf(),
2009
- };
2010
- }
2011
- function getLast12Months(date) {
2012
- return {
2013
- since: date.subtract(12, 'month').startOf('month').valueOf(),
2014
- until: date.subtract(1, 'month').endOf('month').valueOf(),
2015
- };
2016
- }
2017
- function getLastYear(date) {
2018
- return {
2019
- since: date.subtract(1, 'year').startOf('year').valueOf(),
2020
- until: date.subtract(1, 'year').endOf('year').valueOf(),
2021
- };
2022
- }
2023
- const getMonthAndYearByDateFilter = (month, year, date) => {
2024
- const endDate = dayjs(date);
2025
- const endMonthFilter = endDate.month();
2026
- const endYearFilter = endDate.year();
2027
- if (endYearFilter !== year || endMonthFilter !== month) {
2028
- const prev = endDate.subtract(1, 'month');
2029
- return {
2030
- month: prev.month(),
2031
- year: prev.year(),
2032
- };
2033
- }
2034
- return { month, year };
2035
- };
2036
-
2037
- var CompareDateTimePickerAlias;
2038
- (function (CompareDateTimePickerAlias) {
2039
- CompareDateTimePickerAlias["NO_COMPARISON"] = "noComparison";
2040
- CompareDateTimePickerAlias["PREVIOUS_PERIOD"] = "previousPeriod";
2041
- CompareDateTimePickerAlias["PREVIOUS_WEEK"] = "previousWeek";
2042
- CompareDateTimePickerAlias["PREVIOUS_MONTH"] = "previousMonth";
2043
- CompareDateTimePickerAlias["PREVIOUS_QUARTER"] = "previousQuarter";
2044
- CompareDateTimePickerAlias["PREVIOUS_YEAR"] = "previousYear";
2045
- })(CompareDateTimePickerAlias || (CompareDateTimePickerAlias = {}));
2046
- const PREVIOUS_PERIOD_FILTER = {
2047
- title: 'Previous period',
2048
- alias: CompareDateTimePickerAlias.PREVIOUS_PERIOD,
2049
- since: 0,
2050
- until: 0,
2051
- };
2052
- const DATE_TIME_COMPARISON_FILTERS = [
2053
- {
2054
- title: 'No comparison',
2055
- alias: CompareDateTimePickerAlias.NO_COMPARISON,
2056
- since: 0,
2057
- until: 0,
2058
- },
2059
- PREVIOUS_PERIOD_FILTER,
2060
- {
2061
- title: 'Previous week',
2062
- alias: CompareDateTimePickerAlias.PREVIOUS_WEEK,
2063
- since: 0,
2064
- until: 0,
2065
- },
2066
- {
2067
- title: 'Previous quarter',
2068
- alias: CompareDateTimePickerAlias.PREVIOUS_QUARTER,
2069
- since: 0,
2070
- until: 0,
2071
- },
2072
- {
2073
- title: 'Previous month',
2074
- alias: CompareDateTimePickerAlias.PREVIOUS_MONTH,
2075
- since: 0,
2076
- until: 0,
2077
- },
2078
- {
2079
- title: 'Previous year',
2080
- alias: CompareDateTimePickerAlias.PREVIOUS_YEAR,
2081
- since: 0,
2082
- until: 0,
2083
- },
2084
- ];
2085
- const COMPARE_DATE_TIME_FILTERS_MAP = {
2086
- [CompareDateTimePickerAlias.NO_COMPARISON]: getNoComparison,
2087
- [CompareDateTimePickerAlias.PREVIOUS_PERIOD]: getPreviousPeriod,
2088
- [CompareDateTimePickerAlias.PREVIOUS_WEEK]: getPreviousWeek,
2089
- [CompareDateTimePickerAlias.PREVIOUS_QUARTER]: getPreviousQuarter,
2090
- [CompareDateTimePickerAlias.PREVIOUS_MONTH]: getPreviousMonth,
2091
- [CompareDateTimePickerAlias.PREVIOUS_YEAR]: getPreviousYear,
2092
- };
2093
-
2094
- const useDateTimeFilter = () => {
2095
- const currentDate = dayjsTzToLocalTZ().startOf('day');
2096
- const mappings = getDateTimeFilterMapping();
2097
- const TODAY_CONFIG = mappings[MainDateTimePickerAlias.TODAY];
2098
- const TODAY_DATE_RANGE = {
2099
- ...TODAY_CONFIG,
2100
- ...TODAY_CONFIG.getDateRange(currentDate),
2101
- };
2102
- const YESTERDAY_CONFIG = mappings[MainDateTimePickerAlias.YESTERDAY];
2103
- const YESTERDAY_DATE_RANGE = {
2104
- ...YESTERDAY_CONFIG,
2105
- ...YESTERDAY_CONFIG.getDateRange(currentDate),
2106
- };
2107
- const LAST_7_DAYS_CONFIG = mappings[MainDateTimePickerAlias.LAST_7_DAYS];
2108
- const LAST_7_DAYS_DATE_RANGE = {
2109
- ...LAST_7_DAYS_CONFIG,
2110
- ...LAST_7_DAYS_CONFIG.getDateRange(currentDate),
2111
- };
2112
- const LAST_30_DAYS_CONFIG = mappings[MainDateTimePickerAlias.LAST_30_DAYS];
2113
- const LAST_30_DAYS_DATE_RANGE = {
2114
- ...LAST_30_DAYS_CONFIG,
2115
- ...LAST_30_DAYS_CONFIG.getDateRange(currentDate),
2116
- };
2117
- const LAST_90_DAYS_CONFIG = mappings[MainDateTimePickerAlias.LAST_90_DAYS];
2118
- const LAST_90_DAYS_DATE_RANGE = {
2119
- ...LAST_90_DAYS_CONFIG,
2120
- ...LAST_90_DAYS_CONFIG.getDateRange(currentDate),
2121
- };
2122
- const LAST_365_DAYS_CONFIG = mappings[MainDateTimePickerAlias.LAST_365_DAYS];
2123
- const LAST_365_DAYS_DATE_RANGE = {
2124
- ...LAST_365_DAYS_CONFIG,
2125
- ...LAST_365_DAYS_CONFIG.getDateRange(currentDate),
2126
- };
2127
- const LAST_MONTH_CONFIG = mappings[MainDateTimePickerAlias.LAST_MONTH];
2128
- const LAST_MONTH_DATE_RANGE = {
2129
- ...LAST_MONTH_CONFIG,
2130
- ...LAST_MONTH_CONFIG.getDateRange(currentDate),
2131
- };
2132
- const LAST_12_MONTHS_CONFIG = mappings[MainDateTimePickerAlias.LAST_12_MONTHS];
2133
- const LAST_12_MONTHS_DATE_RANGE = {
2134
- ...LAST_12_MONTHS_CONFIG,
2135
- ...LAST_12_MONTHS_CONFIG.getDateRange(currentDate),
2136
- };
2137
- const LAST_YEAR_CONFIG = mappings[MainDateTimePickerAlias.LAST_YEAR];
2138
- const LAST_YEAR_DATE_RANGE = {
2139
- ...LAST_YEAR_CONFIG,
2140
- ...LAST_YEAR_CONFIG.getDateRange(currentDate),
2141
- };
2142
- const DATE_TIME_FILTERS = [
2143
- TODAY_DATE_RANGE,
2144
- YESTERDAY_DATE_RANGE,
2145
- LAST_7_DAYS_DATE_RANGE,
2146
- LAST_30_DAYS_DATE_RANGE,
2147
- LAST_90_DAYS_DATE_RANGE,
2148
- LAST_365_DAYS_DATE_RANGE,
2149
- LAST_MONTH_DATE_RANGE,
2150
- LAST_12_MONTHS_DATE_RANGE,
2151
- LAST_YEAR_DATE_RANGE,
2152
- ];
2153
- return {
2154
- DATE_TIME_FILTERS,
2155
- LAST_7_DAYS_DATE_RANGE,
2156
- LAST_30_DAYS_DATE_RANGE,
2157
- };
2158
- };
2159
-
2160
- const DateTimePickerContext = createContext({
2161
- dateTimePicked: {
2162
- since: dayjsTz().valueOf(),
2163
- until: dayjsTz().valueOf(),
2164
- title: 'Today',
2165
- alias: 'today',
2166
- },
2167
- compareDateTimePicked: PREVIOUS_PERIOD_FILTER,
2168
- setDateTimePicked: () => { },
2169
- setCompareDateTimePicked: () => { },
2170
- resetDateVersion: () => { },
2171
- });
2172
- const DateTimePickerProvider = ({ children, initDate, initDateCompare, }) => {
2173
- const [dateTimePicked, setDateTimePicked] = useState(initDate || {
2174
- since: dayjsTz().set('hour', 0).valueOf(),
2175
- until: dayjsTz().set('hour', 0).valueOf(),
2176
- title: 'Today',
2177
- alias: 'today',
2178
- });
2179
- const { DATE_TIME_FILTERS } = useDateTimeFilter();
2180
- const getCompareDateTimePicked = useCallback((alias, source = dateTimePicked) => {
2181
- return {
2182
- ...PREVIOUS_PERIOD_FILTER,
2183
- ...COMPARE_DATE_TIME_FILTERS_MAP[alias]({
2184
- since: source.since,
2185
- until: source.until,
2186
- alias: source.alias,
2187
- }),
2188
- };
2189
- }, [dateTimePicked]);
2190
- const [compareDateTimePicked, setCompareDateTimePicked] = useState(initDateCompare || getCompareDateTimePicked(CompareDateTimePickerAlias.PREVIOUS_PERIOD));
2191
- const updateCompareDateTimePicked = useCallback((source) => {
2192
- if (compareDateTimePicked.alias === 'custom' ||
2193
- compareDateTimePicked.alias === CompareDateTimePickerAlias.NO_COMPARISON)
2194
- return;
2195
- setCompareDateTimePicked(getCompareDateTimePicked(compareDateTimePicked.alias, source));
2196
- }, [compareDateTimePicked, getCompareDateTimePicked]);
2197
- const resetDateVersion = () => {
2198
- const since = dayjs(dateTimePicked.since).startOf('day').valueOf();
2199
- const until = dayjs(dateTimePicked.until).startOf('day').valueOf();
2200
- const dateFilter = DATE_TIME_FILTERS.find((filter) => filter.since === since && filter.until === until);
2201
- setDateTimePicked({
2202
- ...dateTimePicked,
2203
- isVersion: false,
2204
- versionId: undefined,
2205
- isCurrentVersion: false,
2206
- description: '',
2207
- title: dateFilter?.title || dateTimePicked.title,
2208
- alias: dateFilter?.alias || 'custom',
2209
- });
2210
- };
2211
- const onSetDateTimePicked = useCallback((value) => {
2212
- setDateTimePicked(value);
2213
- updateCompareDateTimePicked(value);
2214
- }, [updateCompareDateTimePicked]);
2215
- return (jsx(DateTimePickerContext.Provider, { value: {
2216
- dateTimePicked,
2217
- setDateTimePicked: onSetDateTimePicked,
2218
- compareDateTimePicked,
2219
- setCompareDateTimePicked,
2220
- resetDateVersion,
2221
- }, children: children }));
2222
- };
2223
- const useDateTimePickerContext = () => {
2224
- const context = useContext(DateTimePickerContext);
2225
- if (!context) {
2226
- throw new Error('useDateTimePickerContext must be used within a DateTimePickerProvider');
2227
- }
2228
- return context;
2229
- };
2230
-
2231
- const useDateTimePicker = ({ ranges, initialPicked, onApply }) => {
2232
- const { DATE_TIME_FILTERS } = useDateTimeFilter();
2233
- const allRanges = ranges || DATE_TIME_FILTERS;
2234
- const { dateTimePicked, setDateTimePicked } = useDateTimePickerContext();
2235
- const [dateRange, setDateRange] = useState(dateTimePicked);
2236
- const [{ month, year }, setDate] = useState({
2237
- month: dayjs(dateTimePicked.since).month(),
2238
- year: dayjs(dateTimePicked.since).year(),
2239
- });
2240
- useEffect(() => {
2241
- if (dateTimePicked) {
2242
- const untilDate = new Date(dateTimePicked.until);
2243
- const monthDiff = (referenceDate, newDate) => {
2244
- return newDate.month - referenceDate.month + 12 * (referenceDate.year - newDate.year);
2245
- };
2246
- monthDiff({ year, month }, {
2247
- year: untilDate.getFullYear(),
2248
- month: untilDate.getMonth(),
2249
- });
2250
- // if (monthDifference > 1 || monthDifference < 0) {
2251
- // setDate({
2252
- // month: untilDate.getMonth(),
2253
- // year: untilDate.getFullYear(),
2254
- // });
2255
- // }
2256
- }
2257
- }, [dateTimePicked, month, year]);
2258
- const onMonthChange = (month, year) => {
2259
- setDate({ month, year });
2260
- };
2261
- const onCalendarChange = (value) => {
2262
- const { start, end, alias } = value;
2263
- const customDateRange = {
2264
- alias: 'custom',
2265
- title: 'Custom',
2266
- since: start.getTime(),
2267
- until: end.getTime(),
2268
- };
2269
- const newDateRange = allRanges.find((range) => {
2270
- const isSameAlias = range.alias === alias;
2271
- const isSameUntil = range.until === end.getTime();
2272
- const isSameSince = range.since === start.getTime();
2273
- // const isSameVersionId = !!range.versionId && !!versionId && range.versionId === versionId;
2274
- const isSameTime = isSameSince && isSameUntil;
2275
- return isSameAlias || isSameTime;
2276
- });
2277
- const finalDateRange = newDateRange || initialPicked || customDateRange;
2278
- setDateRange(finalDateRange);
2279
- };
2280
- const onChange = ({ end }) => {
2281
- setDate(getMonthAndYearByDateFilter(month, year, end));
2282
- };
2283
- const apply = () => {
2284
- setDateTimePicked(dateRange);
2285
- onApply?.(dateRange);
2286
- };
2287
- const cancel = () => {
2288
- setDateRange(dateTimePicked);
2289
- };
2290
- useEffect(() => {
2291
- if (dateTimePicked) {
2292
- setDateRange(dateTimePicked);
2293
- setDate({
2294
- month: dayjs(dateTimePicked.since).month(),
2295
- year: dayjs(dateTimePicked.since).year(),
2296
- });
2297
- }
2298
- }, [dateTimePicked]);
2299
- return {
2300
- month,
2301
- year,
2302
- setDate,
2303
- dateRange,
2304
- apply,
2305
- cancel,
2306
- dateTimePicked,
2307
- onChange,
2308
- onMonthChange,
2309
- onCalendarChange,
2310
- };
2311
- };
2312
-
2313
- const useVersionDateTimeFilters = (versions) => {
2314
- const { t } = useTranslation();
2315
- const rangers = useMemo(() => {
2316
- if (!versions?.length)
2317
- return [];
2318
- return convertToDateTimeFilters(versions);
2319
- }, [versions]);
2320
- const rangeAddition = {
2321
- title: t('Experiment periods'),
2322
- rangers,
2323
- };
2324
- return { rangeAddition };
2325
- };
2326
-
2327
- function DateTimeFilterInputs({ onBlur, dateRange, setDateTimePicked }) {
2328
- const [isFocus, setIsFocus] = useState(false);
2329
- const [inputValues, setInputValues] = useState({});
2330
- const formatDisplayDate = useCallback((timestamp, isEnd = false) => {
2331
- if (!dateRange.isVersion || (isEnd && dateRange.isCurrentVersion))
2332
- return formatDate(timestamp, 'FULL');
2333
- return formatDate(timestamp, 'FULL_WITH_TIME');
2334
- }, [dateRange.isVersion, dateRange.isCurrentVersion]);
2335
- useEffect(() => {
2336
- if (isFocus)
2337
- return;
2338
- setInputValues({
2339
- since: formatDisplayDate(dateRange.since),
2340
- until: formatDisplayDate(dateRange.until, true),
2341
- });
2342
- }, [dateRange, formatDisplayDate]);
2343
- function handleStartInputValueChange(value) {
2344
- setInputValues((prevState) => {
2345
- return { ...prevState, since: value };
2346
- });
2347
- if (isValidDate(value)) {
2348
- const newSinceDate = convertDateToTz(value).startOf('day');
2349
- const untilDate = convertDateToTz(dateRange.until).endOf('day');
2350
- const endDate = newSinceDate.isAfter(untilDate) ? newSinceDate.endOf('day') : untilDate;
2351
- setDateTimePicked({
2352
- start: dayjsTzToLocalTZ(newSinceDate).toDate(),
2353
- end: dayjsTzToLocalTZ(endDate).toDate(),
2354
- });
2355
- }
2356
- }
2357
- function handleEndInputValueChange(value) {
2358
- setInputValues((prevState) => ({ ...prevState, until: value }));
2359
- if (isValidDate(value)) {
2360
- const nowEndOfDay = dayjsTz().endOf('day');
2361
- const newUntilDate = convertDateToTz(value).endOf('day');
2362
- const clampedUntil = newUntilDate.isAfter(nowEndOfDay) ? nowEndOfDay : newUntilDate;
2363
- const sinceDate = convertDateToTz(dateRange.since).startOf('day');
2364
- const startDate = clampedUntil.isBefore(sinceDate) ? clampedUntil.startOf('day') : sinceDate;
2365
- setDateTimePicked({
2366
- start: dayjsTzToLocalTZ(startDate).toDate(),
2367
- end: dayjsTzToLocalTZ(clampedUntil).toDate(),
2368
- });
2369
- }
2370
- }
2371
- function handleInputBlur() {
2372
- setIsFocus(false);
2373
- setInputValues({
2374
- since: formatDisplayDate(dateRange.since),
2375
- until: formatDisplayDate(dateRange.until, true),
2376
- });
2377
- onBlur && onBlur();
2378
- }
2379
- function handleFocusStartInput() {
2380
- setIsFocus(true);
2381
- setInputValues({
2382
- ...inputValues,
2383
- since: formatDate(dateRange.since, 'YMD'),
2384
- });
2385
- }
2386
- function handleFocusEndInput() {
2387
- setIsFocus(true);
2388
- setInputValues({
2389
- ...inputValues,
2390
- until: formatDate(dateRange.until, 'YMD'),
2391
- });
2392
- }
2393
- return (jsxs(InlineGrid, { gap: "200", columns: "1fr auto 1fr", children: [jsx(TextField, { role: "combobox", label: 'Since', labelHidden: true,
2394
- // prefix={<Icon source={CalendarIcon} />}
2395
- 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,
2396
- // prefix={<Icon source={CalendarIcon} />}
2397
- value: dateRange.until ? inputValues.until : 'MMMM D, YYYY', onChange: handleEndInputValueChange, onBlur: () => handleInputBlur(), onFocus: () => handleFocusEndInput(), autoComplete: "off" })] }));
2398
- }
2399
-
2400
- function DateTimeFilterAddition(props) {
2401
- const { setDateTimePicked, dateTimePicked, rangeAddition, allRanges } = props;
2402
- const { value: isExpanded, toggle: toggleExpanded } = useToggle(true);
2403
- const rangesAdditions = rangeAddition?.rangers || [];
2404
- const handleChangeFilterByOption = (value) => {
2405
- const alias = value[0];
2406
- const result = allRanges.find((range) => range.alias === alias) || allRanges[0];
2407
- setDateTimePicked({
2408
- start: dayjsTz(result?.since).toDate(),
2409
- end: dayjsTz(result?.until).toDate(),
2410
- alias: result?.alias,
2411
- });
2412
- };
2413
- const options = rangesAdditions.map((range) => {
2414
- const selected = dateTimePicked.alias === range.alias;
2415
- return {
2416
- value: range.alias,
2417
- 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})` })] }))] })),
2418
- };
2419
- });
2420
- if (!rangeAddition || rangesAdditions.length === 0)
2421
- return;
2422
- 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 }) })] }));
2423
- }
2424
-
2425
- function DateTimeFilters(props) {
2426
- const { setDateTimePicked, dateTimePicked, allRanges, isCompare } = props;
2427
- const { DATE_TIME_FILTERS } = useDateTimeFilter();
2428
- const { mdDown } = useBreakpoints();
2429
- const rangesDefault = isCompare ? [...DATE_TIME_COMPARISON_FILTERS] : [...DATE_TIME_FILTERS];
2430
- const handleChangeFilterBySelect = (value) => {
2431
- const result = allRanges.find(({ title, alias }) => title === value || alias === value) || allRanges[0];
2432
- setDateTimePicked({
2433
- start: dayjsTz(result?.since).toDate(),
2434
- end: dayjsTz(result?.until).toDate(),
2435
- alias: result?.alias,
2436
- });
2437
- };
2438
- const handleChangeFilterByOption = (value) => {
2439
- const result = allRanges.find((range) => range.alias === value[0]) || allRanges[0];
2440
- setDateTimePicked({
2441
- start: dayjsTz(result?.since).toDate(),
2442
- end: dayjsTz(result?.until).toDate(),
2443
- alias: result?.alias,
2444
- });
2445
- };
2446
- 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) => ({
2447
- value: range.alias,
2448
- label: range.title,
2449
- })), selected: dateTimePicked ? [dateTimePicked.alias] : [], onChange: (value) => handleChangeFilterByOption(value) })] }) }) })) }));
2450
- }
2451
-
2452
- const useCompareDateTimePicker = ({ ranges, onApply }) => {
2453
- const allRanges = ranges || DATE_TIME_COMPARISON_FILTERS;
2454
- const { compareDateTimePicked, setCompareDateTimePicked } = useDateTimePickerContext();
2455
- const { dateTimePicked: mainDateRange } = useDateTimePickerContext();
2456
- const [dateRange, setDateRange] = useState(compareDateTimePicked);
2457
- const [{ month, year }, setDate] = useState({
2458
- month: dayjsTz(compareDateTimePicked.since).month(),
2459
- year: dayjsTz(compareDateTimePicked.since).year(),
2460
- });
2461
- const onMonthChange = (month, year) => {
2462
- setDate({ month, year });
2463
- };
2464
- const onCalendarChange = ({ start, end, alias }) => {
2465
- const newDateRange = allRanges.find((range) => {
2466
- return range.alias === alias;
2467
- });
2468
- // If the alias is not found, set the custom date range
2469
- if (!newDateRange) {
2470
- setDateRange({
2471
- alias: 'custom',
2472
- title: 'Custom',
2473
- since: start.getTime(),
2474
- until: end.getTime(),
2475
- });
2476
- return;
2477
- }
2478
- setDateRange({
2479
- ...newDateRange,
2480
- ...COMPARE_DATE_TIME_FILTERS_MAP[alias]({
2481
- since: mainDateRange.since,
2482
- until: mainDateRange.until,
2483
- }),
2484
- });
2485
- };
2486
- const apply = () => {
2487
- setCompareDateTimePicked(dateRange);
2488
- onApply?.(dateRange);
2489
- };
2490
- const cancel = () => {
2491
- setDateRange(compareDateTimePicked);
2492
- };
2493
- const onChange = ({ end }) => {
2494
- setDate(getMonthAndYearByDateFilter(month, year, end));
2495
- };
2496
- return {
2497
- month,
2498
- year,
2499
- setDate,
2500
- dateRange,
2501
- apply,
2502
- cancel,
2503
- compareDateTimePicked,
2504
- onChange,
2505
- onMonthChange,
2506
- onCalendarChange,
2507
- };
2508
- };
2509
-
2510
- const BaseTimePicker = (props) => {
2511
- const { dateTimeFilters, rangeAddition, popoverProps, activatorProps, actionProps, isCompare, buttonValue, activator, } = props;
2512
- const initialPicked = rangeAddition?.initialPicked;
2513
- const ranges = [...(dateTimeFilters || []), ...(rangeAddition?.rangers || [])];
2514
- const useHookDateTimePicker = isCompare ? useCompareDateTimePicker : useDateTimePicker;
2515
- const { month, year, dateRange, apply, cancel, onMonthChange, onCalendarChange, onChange } = useHookDateTimePicker({
2516
- ranges,
2517
- initialPicked,
2518
- onApply: props.onApply,
2519
- });
2520
- const { t } = useTranslation();
2521
- const { mdDown, lgUp } = useBreakpoints();
2522
- const shouldShowMultiMonth = lgUp;
2523
- const rawTooltipContent = useMemo(() => {
2524
- // Only show tooltip when selecting Period (isVersion)
2525
- if (!dateRange.isVersion || !dateRange.since || !dateRange.until)
2526
- return;
2527
- return formatDateTimeRange({
2528
- since: dateRange.since,
2529
- until: dateRange.until,
2530
- isShowNow: dateRange.isCurrentVersion,
2531
- });
2532
- }, [dateRange.since, dateRange.until, dateRange.isVersion, dateRange.isCurrentVersion]);
2533
- const [popoverActive, setPopoverActive] = useState(false);
2534
- // Freeze tooltip content while popover is open to prevent button remount (focus/CSS loss)
2535
- const datePickerRef = useRef(null);
2536
- const tooltipContentRef = useRef(rawTooltipContent);
2537
- if (!popoverActive)
2538
- tooltipContentRef.current = rawTooltipContent;
2539
- const tooltipContent = tooltipContentRef.current;
2540
- //@ts-ignore
2541
- function nodeContainsDescendant(rootNode, descendant) {
2542
- if (rootNode === descendant) {
2543
- return true;
2544
- }
2545
- let parent = descendant.parentNode;
2546
- while (parent != null) {
2547
- if (parent === rootNode) {
2548
- return true;
2549
- }
2550
- parent = parent.parentNode;
2551
- }
2552
- return false;
2553
- }
2554
- //@ts-ignore
2555
- function isNodeWithinPopover(node) {
2556
- return datePickerRef?.current ? nodeContainsDescendant(datePickerRef.current, node) : false;
2557
- }
2558
- //@ts-ignore
2559
- function handleInputBlur({ relatedTarget }) {
2560
- const isRelatedTargetWithinPopover = relatedTarget != null && isNodeWithinPopover(relatedTarget);
2561
- // If focus moves from the TextField to the Popover
2562
- // we don't want to close the popover
2563
- if (isRelatedTargetWithinPopover) {
2564
- return;
2565
- }
2566
- setPopoverActive(false);
2567
- }
2568
- function applyFunc() {
2569
- apply();
2570
- setPopoverActive(false);
2571
- }
2572
- function cancelFunc() {
2573
- cancel();
2574
- setPopoverActive(false);
2575
- }
2576
- const handleTogglePopover = () => {
2577
- if (isCompare) {
2578
- return;
2579
- }
2580
- setPopoverActive(!popoverActive);
2581
- };
2582
- const onChangeDateTimeFilter = (data) => {
2583
- onCalendarChange(data);
2584
- onChange(data);
2585
- };
2586
- 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: {
2587
- xs: '1fr',
2588
- md: 'max-content max-content',
2589
- }, 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
2590
- ? undefined
2591
- : {
2592
- start: dayjs(dateRange.since).toDate(),
2593
- end: dayjs(dateRange.until).toDate(),
2594
- }, onMonthChange: onMonthChange, onChange: onCalendarChange, multiMonth: shouldShowMultiMonth, allowRange: true, disableDatesAfter: dayjsTzToDate() }) }), actionProps && (jsx(GButton, { ...actionProps, onClick: () => {
2595
- setPopoverActive(false);
2596
- actionProps.onClick?.();
2597
- } }))] }) })] }) }) }), 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') })] }) }) }) })] }) }));
2598
- };
2599
-
2600
- const CompareTimePicker = (props) => {
2601
- const { rangeAddition, popoverProps } = props;
2602
- const initialPicked = rangeAddition?.initialPicked;
2603
- const dateTimeFilters = DATE_TIME_COMPARISON_FILTERS;
2604
- const ranges = [...dateTimeFilters, ...(rangeAddition?.rangers || [])];
2605
- const { t } = useTranslation();
2606
- const { compareDateTimePicked } = useCompareDateTimePicker({ ranges, initialPicked });
2607
- const buttonValue = useMemo(() => {
2608
- if (compareDateTimePicked.alias === CompareDateTimePickerAlias.NO_COMPARISON) {
2609
- return t('No comparison');
2610
- }
2611
- return t('Compare to: {{value}}', {
2612
- value: getDateRangeTitle(compareDateTimePicked.since, compareDateTimePicked.until),
2613
- });
2614
- }, [compareDateTimePicked, t]);
2615
- return (jsx(BaseTimePicker, { dateTimeFilters: dateTimeFilters, rangeAddition: rangeAddition, popoverProps: popoverProps, isCompare: true, buttonValue: buttonValue }));
2616
- };
2617
-
2618
- const MainTimePicker = (props) => {
2619
- const { rangeAddition, popoverProps, activator, onApply, activatorProps, actionProps } = props;
2620
- const { DATE_TIME_FILTERS } = useDateTimeFilter();
2621
- const dateTimeFilters = DATE_TIME_FILTERS;
2622
- const additionalRanges = rangeAddition?.rangers || [];
2623
- const initialPicked = rangeAddition?.initialPicked;
2624
- const ranges = [...dateTimeFilters, ...additionalRanges];
2625
- const { dateTimePicked } = useDateTimePicker({ ranges, initialPicked });
2626
- const getButtonValue = () => {
2627
- if (dateTimePicked.isVersion && additionalRanges.length > 0) {
2628
- const time = dateTimePicked.description ? `at ${dateTimePicked.description}` : '';
2629
- return `Period: ${dateTimePicked.title} ${time}`;
2630
- }
2631
- if (dateTimePicked.alias === 'custom') {
2632
- return getDateRangeTitle(dateTimePicked.since, dateTimePicked.until);
2633
- }
2634
- return dateTimePicked.title;
2635
- };
2636
- return (jsx(BaseTimePicker, { activatorProps: activatorProps, dateTimeFilters: dateTimeFilters, rangeAddition: rangeAddition, popoverProps: popoverProps, actionProps: actionProps, buttonValue: getButtonValue(), activator: activator, onApply: onApply }));
2637
- };
2638
-
2639
- const GTimePicker = (props) => {
2640
- const { isCompare, ...timePickerProps } = props;
2641
- return (jsxs(InlineStack, { gap: "200", children: [jsx(MainTimePicker, { ...timePickerProps }), isCompare && (jsx(CompareTimePicker, { rangeAddition: timePickerProps.rangeAddition, popoverProps: timePickerProps.popoverProps }))] }));
2642
- };
2643
-
2644
- function isBrowser() {
2645
- return typeof window !== 'undefined';
2646
- }
2647
- const useIsStickyById = ({ id, stickyTop, threshold = 0, enabled = true }) => {
2648
- const [isSticky, setIsSticky] = useState(false);
2649
- useEffect(() => {
2650
- if (!enabled || !isBrowser())
2651
- return;
2652
- const el = document.getElementById(id);
2653
- if (!el)
2654
- return;
2655
- const checkSticky = () => {
2656
- const rect = el.getBoundingClientRect();
2657
- setIsSticky(rect.top <= stickyTop + threshold);
2658
- };
2659
- checkSticky();
2660
- window.addEventListener('scroll', checkSticky, { passive: true });
2661
- window.addEventListener('resize', checkSticky);
2662
- return () => {
2663
- window.removeEventListener('scroll', checkSticky);
2664
- window.removeEventListener('resize', checkSticky);
2665
- };
2666
- }, [id, stickyTop, threshold, enabled]);
2667
- return isSticky;
2668
- };
2669
-
2670
- // Border is deferred until the row is actually stuck so it doesn't flash on initial render.
2671
- const useStickyFilterBoxProps = ({ id }) => {
2672
- const { isMobileView } = useWindowSize();
2673
- const enabled = isMobileView && Boolean(id);
2674
- const isStuck = useIsStickyById({ id, stickyTop: 0, enabled });
2675
- if (!enabled)
2676
- return {};
2677
- return {
2678
- position: 'sticky',
2679
- insetBlockStart: '0',
2680
- zIndex: '10',
2681
- background: 'bg',
2682
- paddingBlock: '200',
2683
- ...(isStuck && { borderBlockEndWidth: '025', borderColor: 'border' }),
2684
- };
2685
- };
2686
-
2687
- export { ANALYTICS_METRIC_TOOLTIP, AnalyticModeSelector, CAMPAIGN_BACKGROUND_MAIN, CHART_MIN_HEIGHT, COMPARE_DATE_TIME_FILTERS_MAP, CompareDateTimePickerAlias, ConvertMoneyProvider, CurrencySelector, DATE_TIME_COMPARISON_FILTERS, DEFAULT_CURRENCY_ANALYTIC, DEFAULT_CURRENT_PERIOD_LABEL, DEFAULT_PREVIOUS_PERIOD_LABEL, DateTimeFilterInputs, DateTimeFilters, DateTimePickerContext, DateTimePickerProvider, GSelectableMetricChartCard, GTimePicker, MainDateTimePickerAlias, MetricChartProvider, 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, useConvertMoneyContext, useCurrencyRatesStore, useDateTimeFilter, useDateTimePicker, useDateTimePickerContext, useIsStickyById, useStickyFilterBoxProps, useVersionDateTimeFilters };
1021
+ export { ANALYTICS_METRIC_TOOLTIP, CAMPAIGN_BACKGROUND_MAIN, CHART_MIN_HEIGHT, DEFAULT_CURRENT_PERIOD_LABEL, DEFAULT_PREVIOUS_PERIOD_LABEL, EAnalyticColumnKey, EDeviceType, EMetricKey, ETrafficSourceType, EVisitorType, GSelectableMetricChartCard, MetricDonutChartCard, PLACEHOLDER_VALUE, SERIES_COLORS, SingleMetricChartCard, TARGET_CHANNEL, TARGET_DEVICES, TARGET_VISITOR, THUMB_PRODUCT_DEFAULT, TREND_TONE };