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