@liiift-studio/sanity-visitor-insights 0.58.0 → 0.60.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +90 -89
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +78 -77
- package/dist/index.mjs.map +1 -1
- package/dist/{ranges-DBbZ0tg7.d.mts → ranges-CMADS44I.d.mts} +1 -19
- package/dist/{ranges-DBbZ0tg7.d.ts → ranges-CMADS44I.d.ts} +1 -19
- package/dist/server.d.mts +2 -2
- package/dist/server.d.ts +2 -2
- package/dist/server.js +7 -13
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +7 -13
- package/dist/server.mjs.map +1 -1
- package/package.json +1 -1
- package/src/reportData.ts +0 -19
- package/src/server/reports/measurementHealth.ts +1 -7
- package/src/server/reports/reports.test.ts +7 -4
- package/src/studio/Figure.tsx +2 -2
- package/src/studio/panels.test.tsx +89 -34
- package/src/studio/panels.tsx +133 -86
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as sanity from 'sanity';
|
|
2
2
|
import React from 'react';
|
|
3
|
-
import { R as ReportEnvelope, a as ReportName, b as RangeKey, M as MetricValue, A as AcquisitionData, c as MeasurementHealthData, D as DiagnosticReport, J as JourneyData, T as TypefaceInterestData } from './ranges-
|
|
4
|
-
export { C as CaptureBasis, d as CaptureEstimate, e as CaptureModel, f as CheckStatus, g as Coverage, h as CrossSourceDay, i as
|
|
3
|
+
import { R as ReportEnvelope, a as ReportName, b as RangeKey, M as MetricValue, A as AcquisitionData, c as MeasurementHealthData, D as DiagnosticReport, J as JourneyData, T as TypefaceInterestData } from './ranges-CMADS44I.mjs';
|
|
4
|
+
export { C as CaptureBasis, d as CaptureEstimate, e as CaptureModel, f as CheckStatus, g as Coverage, h as CrossSourceDay, i as DateRange, j as DiagnosticCheck, E as EmailCampaign, k as EventCutover, l as JourneyOutcome, m as JourneySegment, n as JourneyStep, L as LandingPage, o as LicenceTierRow, P as PREEXISTING, p as REPORT_NAMES, q as ReportError, S as SiteAnalyticsConfig, r as SourceName, s as SourceRow, t as SourceStatus, u as TimelineEvent, v as TypefaceInterestRow, U as UnavailableReason, w as coverageForRange, x as estimated, y as isReportName, z as ok, B as partial, F as previousRange, G as resolveRange, H as unavailable, I as validateSiteConfig, K as valueOrNull } from './ranges-CMADS44I.mjs';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Data hook for the Studio panels.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as sanity from 'sanity';
|
|
2
2
|
import React from 'react';
|
|
3
|
-
import { R as ReportEnvelope, a as ReportName, b as RangeKey, M as MetricValue, A as AcquisitionData, c as MeasurementHealthData, D as DiagnosticReport, J as JourneyData, T as TypefaceInterestData } from './ranges-
|
|
4
|
-
export { C as CaptureBasis, d as CaptureEstimate, e as CaptureModel, f as CheckStatus, g as Coverage, h as CrossSourceDay, i as
|
|
3
|
+
import { R as ReportEnvelope, a as ReportName, b as RangeKey, M as MetricValue, A as AcquisitionData, c as MeasurementHealthData, D as DiagnosticReport, J as JourneyData, T as TypefaceInterestData } from './ranges-CMADS44I.js';
|
|
4
|
+
export { C as CaptureBasis, d as CaptureEstimate, e as CaptureModel, f as CheckStatus, g as Coverage, h as CrossSourceDay, i as DateRange, j as DiagnosticCheck, E as EmailCampaign, k as EventCutover, l as JourneyOutcome, m as JourneySegment, n as JourneyStep, L as LandingPage, o as LicenceTierRow, P as PREEXISTING, p as REPORT_NAMES, q as ReportError, S as SiteAnalyticsConfig, r as SourceName, s as SourceRow, t as SourceStatus, u as TimelineEvent, v as TypefaceInterestRow, U as UnavailableReason, w as coverageForRange, x as estimated, y as isReportName, z as ok, B as partial, F as previousRange, G as resolveRange, H as unavailable, I as validateSiteConfig, K as valueOrNull } from './ranges-CMADS44I.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Data hook for the Studio panels.
|
package/dist/index.js
CHANGED
|
@@ -75,7 +75,7 @@ var import_sanity2 = require("sanity");
|
|
|
75
75
|
var import_icons = require("@liiift-studio/sanity-ui-compat/icons");
|
|
76
76
|
|
|
77
77
|
// src/studio/VisitorInsightsTool.tsx
|
|
78
|
-
var
|
|
78
|
+
var import_react4 = __toESM(require("react"));
|
|
79
79
|
var import_sanity_ui_compat4 = require("@liiift-studio/sanity-ui-compat");
|
|
80
80
|
|
|
81
81
|
// src/studio/useReport.ts
|
|
@@ -1166,7 +1166,6 @@ var visuallyHidden = {
|
|
|
1166
1166
|
var import_sanity_ui_compat5 = require("@liiift-studio/sanity-ui-compat");
|
|
1167
1167
|
|
|
1168
1168
|
// src/studio/panels.tsx
|
|
1169
|
-
var import_react4 = __toESM(require("react"));
|
|
1170
1169
|
var import_sanity_ui_compat3 = require("@liiift-studio/sanity-ui-compat");
|
|
1171
1170
|
|
|
1172
1171
|
// src/studio/CrossSourceTimeline.tsx
|
|
@@ -1907,24 +1906,24 @@ var figureRow = {
|
|
|
1907
1906
|
gap: 10,
|
|
1908
1907
|
flexWrap: "wrap"
|
|
1909
1908
|
};
|
|
1910
|
-
var
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1909
|
+
var segmentHeadCell = {
|
|
1910
|
+
textAlign: "left",
|
|
1911
|
+
fontSize: "0.78em",
|
|
1912
|
+
letterSpacing: "0.06em",
|
|
1913
|
+
textTransform: "uppercase",
|
|
1914
|
+
fontWeight: 500,
|
|
1915
|
+
opacity: 0.7,
|
|
1916
|
+
padding: "8px 12px",
|
|
1917
|
+
borderBottom: "1px solid var(--card-border-color, rgba(128,128,128,0.3))",
|
|
1918
|
+
whiteSpace: "nowrap"
|
|
1919
|
+
};
|
|
1920
|
+
var segmentRowCell = {
|
|
1921
|
+
textAlign: "left",
|
|
1922
|
+
fontWeight: 400,
|
|
1923
|
+
padding: "8px 12px",
|
|
1924
|
+
borderBottom: "1px solid var(--card-border-color, rgba(128,128,128,0.18))",
|
|
1925
|
+
verticalAlign: "baseline"
|
|
1926
|
+
};
|
|
1928
1927
|
var sourceLink = {
|
|
1929
1928
|
color: "inherit",
|
|
1930
1929
|
textDecoration: "underline",
|
|
@@ -2200,7 +2199,7 @@ function OverviewPanel({ data, previous, onBrush }) {
|
|
|
2200
2199
|
] }),
|
|
2201
2200
|
(data.campaigns?.length ?? 0) > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_sanity_ui_compat3.Stack, { space: 3, children: [
|
|
2202
2201
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SectionTitle, { title: "Email campaigns" }),
|
|
2203
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 1, muted: true, children: "Clicks are distinct subscribers. Opens are
|
|
2202
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 1, muted: true, children: "Clicks are distinct subscribers. Opens are not shown: Apple Mail fetches images on the recipient\u2019s behalf, so an open is often the mail client rather than a person." }),
|
|
2204
2203
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_sanity_ui_compat3.Text, { size: 1, muted: true, children: [
|
|
2205
2204
|
"The last two columns count what your order book records in the ",
|
|
2206
2205
|
SEND_WINDOW_DAYS,
|
|
@@ -2227,7 +2226,11 @@ function OverviewPanel({ data, previous, onBrush }) {
|
|
|
2227
2226
|
] })
|
|
2228
2227
|
},
|
|
2229
2228
|
{ key: "sent", label: "Sent", numeric: true, sortValue: (c) => c.sent, render: (c) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 1, children: formatCount(c.sent) }) },
|
|
2230
|
-
|
|
2229
|
+
// No Opens column. The caption above the table told the reader, in the tool's
|
|
2230
|
+
// own words, to "sort on clicks, not opens" because Apple Mail Privacy
|
|
2231
|
+
// Protection fetches images on the recipient's behalf. A column whose own
|
|
2232
|
+
// caption instructs you not to read it should not be a column — and the
|
|
2233
|
+
// warning gets shorter as a result.
|
|
2231
2234
|
{ key: "clicks", label: "Clicks", numeric: true, sortValue: (c) => c.clicks, render: (c) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 1, children: formatCount(c.clicks) }) },
|
|
2232
2235
|
{
|
|
2233
2236
|
key: "unsub",
|
|
@@ -2625,11 +2628,51 @@ function rankLine(series, pick) {
|
|
|
2625
2628
|
const ranked = weeklyRank(series.map((d) => ({ date: d.date, value: pick(d) })));
|
|
2626
2629
|
return ranked ? describeRank(ranked) : null;
|
|
2627
2630
|
}
|
|
2631
|
+
function SegmentTable({ segments, dimension }) {
|
|
2632
|
+
if (segments.length < 2) return null;
|
|
2633
|
+
const spine = [...segments].sort((a, b) => b.steps.length - a.steps.length)[0]?.steps ?? [];
|
|
2634
|
+
if (spine.length === 0) return null;
|
|
2635
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_sanity_ui_compat3.Stack, { space: 3, children: [
|
|
2636
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_sanity_ui_compat3.Text, { size: 1, muted: true, children: [
|
|
2637
|
+
"Every ",
|
|
2638
|
+
dimension,
|
|
2639
|
+
" at once. A rate needs ",
|
|
2640
|
+
MIN_RATE_DENOMINATOR,
|
|
2641
|
+
" people at the step before it; below that only the count is shown."
|
|
2642
|
+
] }),
|
|
2643
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { radius: 2, tone: "transparent", border: true, style: { overflowX: "auto", width: "100%" }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("table", { style: { width: "100%", borderCollapse: "collapse", minWidth: 360 }, children: [
|
|
2644
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("caption", { style: visuallyHidden, children: [
|
|
2645
|
+
"Funnel steps by ",
|
|
2646
|
+
dimension
|
|
2647
|
+
] }),
|
|
2648
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("tr", { children: [
|
|
2649
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("th", { scope: "col", style: segmentHeadCell, children: "Step" }),
|
|
2650
|
+
segments.map((segment) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("th", { scope: "col", style: { ...segmentHeadCell, textAlign: "right" }, children: segment.label }, segment.key))
|
|
2651
|
+
] }) }),
|
|
2652
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("tbody", { children: spine.map((step, index) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("tr", { children: [
|
|
2653
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("th", { scope: "row", style: segmentRowCell, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 1, children: step.label }) }),
|
|
2654
|
+
segments.map((segment) => {
|
|
2655
|
+
const cell = segment.steps.find((s) => s.key === step.key);
|
|
2656
|
+
const count = cell ? metricSortValue(cell.count) : null;
|
|
2657
|
+
const before = index > 0 ? metricSortValue(segment.steps.find((s) => s.key === spine[index - 1].key)?.count) : null;
|
|
2658
|
+
const rate = cell?.conversionFromPrevious ?? null;
|
|
2659
|
+
const showRate = index > 0 && rate !== null && before !== null && before >= MIN_RATE_DENOMINATOR;
|
|
2660
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("td", { style: { ...segmentRowCell, textAlign: "right", fontVariantNumeric: "tabular-nums" }, children: count === null ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 1, muted: true, children: "\u2014" }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_sanity_ui_compat3.Stack, { space: 1, children: [
|
|
2661
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 1, children: formatCount(count) }),
|
|
2662
|
+
showRate && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_sanity_ui_compat3.Text, { size: 0, muted: true, children: [
|
|
2663
|
+
formatPercent(rate, 1),
|
|
2664
|
+
" of ",
|
|
2665
|
+
formatCount(before)
|
|
2666
|
+
] })
|
|
2667
|
+
] }) }, segment.key);
|
|
2668
|
+
})
|
|
2669
|
+
] }, step.key)) })
|
|
2670
|
+
] }) })
|
|
2671
|
+
] });
|
|
2672
|
+
}
|
|
2628
2673
|
function JourneyPanel({ data }) {
|
|
2629
|
-
const [segmentKey, setSegmentKey] = import_react4.default.useState(null);
|
|
2630
2674
|
const segments = data.segments ?? [];
|
|
2631
|
-
const
|
|
2632
|
-
const allSteps = segment ? segment.steps : data.steps ?? [];
|
|
2675
|
+
const allSteps = data.steps ?? [];
|
|
2633
2676
|
const shown = allSteps.filter((step) => step.count.status !== "unavailable");
|
|
2634
2677
|
const hiddenSteps = allSteps.filter((step) => step.count.status === "unavailable");
|
|
2635
2678
|
const stages = shown.flatMap(
|
|
@@ -2641,44 +2684,8 @@ function JourneyPanel({ data }) {
|
|
|
2641
2684
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 1, weight: "medium", children: tracked ? "Tracked funnel" : "Independent per-step totals" }),
|
|
2642
2685
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 1, muted: tracked, children: data.approximationNote })
|
|
2643
2686
|
] }) }),
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2647
|
-
"button",
|
|
2648
|
-
{
|
|
2649
|
-
type: "button",
|
|
2650
|
-
role: "radio",
|
|
2651
|
-
"aria-checked": segmentKey === null,
|
|
2652
|
-
style: segmentButton(segmentKey === null),
|
|
2653
|
-
onClick: () => setSegmentKey(null),
|
|
2654
|
-
children: "Everyone"
|
|
2655
|
-
}
|
|
2656
|
-
),
|
|
2657
|
-
segments.map((row) => {
|
|
2658
|
-
const rate = firstStepRate(row.steps);
|
|
2659
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2660
|
-
"button",
|
|
2661
|
-
{
|
|
2662
|
-
type: "button",
|
|
2663
|
-
role: "radio",
|
|
2664
|
-
"aria-checked": segmentKey === row.key,
|
|
2665
|
-
style: segmentButton(segmentKey === row.key),
|
|
2666
|
-
onClick: () => setSegmentKey(row.key),
|
|
2667
|
-
children: [
|
|
2668
|
-
row.label,
|
|
2669
|
-
rate !== null && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: segmentRate, children: formatPercent(rate, 2) })
|
|
2670
|
-
]
|
|
2671
|
-
},
|
|
2672
|
-
row.key
|
|
2673
|
-
);
|
|
2674
|
-
})
|
|
2675
|
-
] }),
|
|
2676
|
-
spread(segments) && /* Said in words, once, where the funnel is. The whole reason to split a funnel
|
|
2677
|
-
is that the halves differ; when they differ by a multiple rather than a
|
|
2678
|
-
margin, the undivided funnel above describes nobody and the reader should
|
|
2679
|
-
be told rather than left to press the buttons and notice. */
|
|
2680
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 1, children: spread(segments) })
|
|
2681
|
-
] }),
|
|
2687
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SegmentTable, { segments, dimension: data.segmentDimension ?? "segment" }),
|
|
2688
|
+
spread(segments) && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 1, children: spread(segments) }),
|
|
2682
2689
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(FunnelChart, { stages, measurement: data.measurement ?? "independent-totals" }),
|
|
2683
2690
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: splitGrid, children: [
|
|
2684
2691
|
(data.outcomes?.length ?? 0) > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
@@ -2926,18 +2933,12 @@ function TypefaceInterestPanel({ data }) {
|
|
|
2926
2933
|
"\xD7 catalogue"
|
|
2927
2934
|
] });
|
|
2928
2935
|
}
|
|
2929
|
-
},
|
|
2930
|
-
{
|
|
2931
|
-
key: "testRate",
|
|
2932
|
-
label: "Test rate",
|
|
2933
|
-
numeric: true,
|
|
2934
|
-
sortValue: (row) => finiteOrNull(row.testRate),
|
|
2935
|
-
exportValue: (row) => {
|
|
2936
|
-
const r = finiteOrNull(row.testRate);
|
|
2937
|
-
return r === null ? null : formatPercent(r, 1);
|
|
2938
|
-
},
|
|
2939
|
-
render: (row) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 1, muted: true, "aria-label": finiteOrNull(row.testRate) === null ? `${row.typeface} test rate unavailable` : void 0, children: finiteOrNull(row.testRate) === null ? "\u2014" : formatPercent(row.testRate, 1) })
|
|
2940
2936
|
}
|
|
2937
|
+
// No Test rate column. It was tested ÷ viewed, rendered muted, from the two
|
|
2938
|
+
// columns immediately to its left — and typefaceInterest's own note says that
|
|
2939
|
+
// where a site maps several tester events onto the step (TDF names three) the
|
|
2940
|
+
// numerator is not a person count, so the ratio ranks page layout as much as
|
|
2941
|
+
// interest. A reader who wants it can see both terms side by side.
|
|
2941
2942
|
]
|
|
2942
2943
|
}
|
|
2943
2944
|
)
|
|
@@ -3092,13 +3093,13 @@ function RangeSelector({
|
|
|
3092
3093
|
onChange,
|
|
3093
3094
|
onCustomChange
|
|
3094
3095
|
}) {
|
|
3095
|
-
const refs = (0,
|
|
3096
|
-
const [pickerOpen, setPickerOpen] = (0,
|
|
3097
|
-
const [draft, setDraft] = (0,
|
|
3098
|
-
|
|
3096
|
+
const refs = (0, import_react4.useRef)([]);
|
|
3097
|
+
const [pickerOpen, setPickerOpen] = (0, import_react4.useState)(value === "custom");
|
|
3098
|
+
const [draft, setDraft] = (0, import_react4.useState)(custom);
|
|
3099
|
+
import_react4.default.useEffect(() => {
|
|
3099
3100
|
setDraft(custom);
|
|
3100
3101
|
}, [custom.start, custom.end]);
|
|
3101
|
-
const onKeyDown = (0,
|
|
3102
|
+
const onKeyDown = (0, import_react4.useCallback)(
|
|
3102
3103
|
(event) => {
|
|
3103
3104
|
const currentIndex = RANGES.findIndex((r) => r.key === value);
|
|
3104
3105
|
let nextIndex = null;
|
|
@@ -3218,8 +3219,8 @@ function SourceStatusRow({ sources }) {
|
|
|
3218
3219
|
] }) });
|
|
3219
3220
|
}
|
|
3220
3221
|
function PanelTabs({ value, onChange }) {
|
|
3221
|
-
const refs = (0,
|
|
3222
|
-
const onKeyDown = (0,
|
|
3222
|
+
const refs = (0, import_react4.useRef)([]);
|
|
3223
|
+
const onKeyDown = (0, import_react4.useCallback)(
|
|
3223
3224
|
(event) => {
|
|
3224
3225
|
const currentIndex = PANELS.findIndex((p) => p.id === value);
|
|
3225
3226
|
let nextIndex = null;
|
|
@@ -3420,7 +3421,7 @@ function isoDaysAgo(days) {
|
|
|
3420
3421
|
return new Date(utcMidnight - days * 864e5).toISOString().slice(0, 10);
|
|
3421
3422
|
}
|
|
3422
3423
|
var COMPARED_TABS = ["overview", "acquisition"];
|
|
3423
|
-
var PanelBoundary = class extends
|
|
3424
|
+
var PanelBoundary = class extends import_react4.default.Component {
|
|
3424
3425
|
constructor(props) {
|
|
3425
3426
|
super(props);
|
|
3426
3427
|
this.state = { error: null, shownFor: props.resetKey };
|
|
@@ -3459,16 +3460,16 @@ var PanelBoundary = class extends import_react5.default.Component {
|
|
|
3459
3460
|
function VisitorInsightsTool(props) {
|
|
3460
3461
|
const apiBaseUrl = props.tool?.options?.apiBaseUrl ?? props.apiBaseUrl ?? "";
|
|
3461
3462
|
const siteLabel = props.tool?.options?.siteLabel ?? props.siteLabel ?? "";
|
|
3462
|
-
const [linked] = (0,
|
|
3463
|
+
const [linked] = (0, import_react4.useState)(() => typeof window === "undefined" ? {} : decodeView(window.location.hash));
|
|
3463
3464
|
const linkedRange = RANGES.some((r) => r.key === linked.range) ? linked.range : null;
|
|
3464
3465
|
const linkedTab = PANELS.some((p) => p.id === linked.tab) ? linked.tab : null;
|
|
3465
|
-
const [range, setRange] = (0,
|
|
3466
|
-
const [rangeBeforeBrush, setRangeBeforeBrush] = (0,
|
|
3467
|
-
const [custom, setCustom] = (0,
|
|
3466
|
+
const [range, setRange] = (0, import_react4.useState)(linkedRange ?? "month");
|
|
3467
|
+
const [rangeBeforeBrush, setRangeBeforeBrush] = (0, import_react4.useState)(linkedRange ?? "month");
|
|
3468
|
+
const [custom, setCustom] = (0, import_react4.useState)(() => linked.from && linked.to ? { start: linked.from, end: linked.to } : { start: isoDaysAgo(30), end: isoDaysAgo(0) });
|
|
3468
3469
|
const atPresent = custom.end >= isoDaysAgo(0);
|
|
3469
|
-
const [compare, setCompare] = (0,
|
|
3470
|
-
const [activePanel, setActivePanel] = (0,
|
|
3471
|
-
|
|
3470
|
+
const [compare, setCompare] = (0, import_react4.useState)("previous-period");
|
|
3471
|
+
const [activePanel, setActivePanel] = (0, import_react4.useState)(linkedTab ?? "overview");
|
|
3472
|
+
import_react4.default.useEffect(() => {
|
|
3472
3473
|
if (typeof window === "undefined") return;
|
|
3473
3474
|
const next = mergeIntoHash(window.location.hash, {
|
|
3474
3475
|
tab: activePanel,
|