@liiift-studio/sanity-visitor-insights 0.62.0 → 0.64.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.js +65 -35
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +65 -35
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/studio/panels.test.tsx +127 -0
- package/src/studio/panels.tsx +111 -51
package/dist/index.js
CHANGED
|
@@ -2074,38 +2074,62 @@ function OverviewPanel({ data, previous, onBrush }) {
|
|
|
2074
2074
|
source: "GA4",
|
|
2075
2075
|
complete: true,
|
|
2076
2076
|
unit: "percent",
|
|
2077
|
-
// Fixed
|
|
2078
|
-
//
|
|
2079
|
-
|
|
2077
|
+
// Fixed at the bottom, open at the top.
|
|
2078
|
+
//
|
|
2079
|
+
// The lower bound is fixed so a site at a flat 20% cannot scale itself
|
|
2080
|
+
// to full height and read as healthy. The UPPER bound is not clamped,
|
|
2081
|
+
// because over-counting is a real fault with its own interpretation
|
|
2082
|
+
// branch — and the card further down this very file refuses the same
|
|
2083
|
+
// clamp in prose, saying `Math.min(1, …)` rendered a tag reporting
|
|
2084
|
+
// 250% of reality as a flat 100% under the heading "How much GA4 is
|
|
2085
|
+
// seeing", i.e. perfect. One quantity, two opposite policies, one
|
|
2086
|
+
// file: the row drew a double-firing tag as a healthy flat line while
|
|
2087
|
+
// the sentence beside it called the over-count out.
|
|
2088
|
+
domain: [0, Math.max(1, ...(data.crossSource ?? []).map((d) => d.vercelPageviews !== null && d.ga4Pageviews !== null && d.vercelPageviews > 0 ? d.ga4Pageviews / d.vercelPageviews : 0))],
|
|
2080
2089
|
points: (data.crossSource ?? []).map((d) => ({
|
|
2081
2090
|
date: d.date,
|
|
2082
|
-
value: d.vercelPageviews !== null && d.ga4Pageviews !== null && d.vercelPageviews > 0 ?
|
|
2091
|
+
value: d.vercelPageviews !== null && d.ga4Pageviews !== null && d.vercelPageviews > 0 ? d.ga4Pageviews / d.vercelPageviews : null
|
|
2083
2092
|
})),
|
|
2084
2093
|
// The most valuable ghost in the chart: a collapse reads as a step away
|
|
2085
2094
|
// from last period's flat line, whether or not the detector fired.
|
|
2086
2095
|
comparison: (previous?.crossSource ?? []).map((d) => ({
|
|
2087
2096
|
date: d.date,
|
|
2088
|
-
value: d.vercelPageviews !== null && d.ga4Pageviews !== null && d.vercelPageviews > 0 ?
|
|
2097
|
+
value: d.vercelPageviews !== null && d.ga4Pageviews !== null && d.vercelPageviews > 0 ? d.ga4Pageviews / d.vercelPageviews : null
|
|
2089
2098
|
}))
|
|
2090
2099
|
}] : [],
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2100
|
+
// ORDERS ALWAYS, revenue only when it covers every order.
|
|
2101
|
+
//
|
|
2102
|
+
// This used to draw revenue whenever ANY day had a revenue figure, and
|
|
2103
|
+
// otherwise orders — never both. Combined with the server filling a day's
|
|
2104
|
+
// revenue as `revenueByDate[date] ?? 0`, that meant a day carrying a real
|
|
2105
|
+
// order with no recorded amount arrived as a measured ZERO, and the row drew
|
|
2106
|
+
// a zero-tick on it: the mark whose own comment says "measured, and it was
|
|
2107
|
+
// nothing".
|
|
2108
|
+
//
|
|
2109
|
+
// At Darden 11 of 69 orders carry an amount, so the flagship chart was
|
|
2110
|
+
// asserting that no sale happened on 58 days that had sales — the package's
|
|
2111
|
+
// founding distinction inverted inside its most prominent encoding. Orders
|
|
2112
|
+
// are exact and complete whatever the amounts say, so they are the row that
|
|
2113
|
+
// is always honest.
|
|
2114
|
+
{
|
|
2101
2115
|
key: "orders",
|
|
2102
2116
|
label: "Orders",
|
|
2103
2117
|
source: "Sanity",
|
|
2104
2118
|
complete: true,
|
|
2105
2119
|
unit: "count",
|
|
2120
|
+
// A sale is an event on a date, not a level that varies day to day.
|
|
2106
2121
|
mark: "events",
|
|
2107
2122
|
points: (data.crossSource ?? []).map((d) => ({ date: d.date, value: d.orders }))
|
|
2108
|
-
}
|
|
2123
|
+
},
|
|
2124
|
+
...revenueCoversEveryOrder(data) ? [{
|
|
2125
|
+
key: "revenue",
|
|
2126
|
+
label: "Revenue",
|
|
2127
|
+
source: "Sanity",
|
|
2128
|
+
complete: true,
|
|
2129
|
+
unit: "money",
|
|
2130
|
+
mark: "events",
|
|
2131
|
+
points: (data.crossSource ?? []).map((d) => ({ date: d.date, value: d.revenue }))
|
|
2132
|
+
}] : []
|
|
2109
2133
|
]
|
|
2110
2134
|
}
|
|
2111
2135
|
),
|
|
@@ -2325,6 +2349,10 @@ function DataHealthPanel({ data, diagnostics }) {
|
|
|
2325
2349
|
const pageviewMax = maxOf([data.ga4Pageviews, data.vercelPageviews]);
|
|
2326
2350
|
const contained = isContainment(data.vercelPageviews, data.ga4Pageviews);
|
|
2327
2351
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_sanity_ui_compat3.Stack, { space: 4, children: [
|
|
2352
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent", border: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_sanity_ui_compat3.Stack, { space: 2, children: [
|
|
2353
|
+
data.shortfallRatio !== null && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 1, weight: "semibold", children: data.shortfallRatio >= 0 ? `GA4 saw ${formatPercent(data.shortfallRatio, 1)} fewer pageviews than Vercel` : `GA4 saw ${formatPercent(-data.shortfallRatio, 1)} more pageviews than Vercel` }),
|
|
2354
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 1, muted: true, children: data.interpretation })
|
|
2355
|
+
] }) }),
|
|
2328
2356
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_sanity_ui_compat3.Stack, { space: 3, children: [
|
|
2329
2357
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SectionTitle, { title: "Pageviews, source against source" }),
|
|
2330
2358
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 1, muted: true, children: "Both counting pageviews. Google Analytics is blockable, so seeing fewer is normal." }),
|
|
@@ -2342,10 +2370,21 @@ function DataHealthPanel({ data, diagnostics }) {
|
|
|
2342
2370
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ComparisonBar, { label: "GA4 pageviews", metric: data.ga4Pageviews, max: pageviewMax })
|
|
2343
2371
|
] })
|
|
2344
2372
|
] }),
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2373
|
+
diagnostics && /* Open, and primary. This is the longest block on the tab and the obvious candidate
|
|
2374
|
+
for folding away — but the tab it sits on exists to answer "what should I fix
|
|
2375
|
+
before trusting any of this", and these checks ARE that answer. Folding it would
|
|
2376
|
+
have left Data health opening on a summary of the problem with the solution behind
|
|
2377
|
+
a click. It stays collapsible so a reader who has read it can get it out of the
|
|
2378
|
+
way. */
|
|
2379
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2380
|
+
Section,
|
|
2381
|
+
{
|
|
2382
|
+
title: "Configuration",
|
|
2383
|
+
subtitle: "What this site has wired up, and what it is missing.",
|
|
2384
|
+
collapsible: true,
|
|
2385
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(DiagnosticsPanel, { data: diagnostics })
|
|
2386
|
+
}
|
|
2387
|
+
),
|
|
2349
2388
|
((data.capture?.estimates?.length ?? 0) > 0 || data.estimatedSessions?.status === "estimated") && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_sanity_ui_compat3.Stack, { space: 3, children: [
|
|
2350
2389
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SectionTitle, { title: "How much GA4 is seeing" }),
|
|
2351
2390
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: cardGrid, children: (data.capture?.estimates ?? []).map((estimate) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent", border: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_sanity_ui_compat3.Stack, { space: 3, children: [
|
|
@@ -2400,21 +2439,6 @@ function DataHealthPanel({ data, diagnostics }) {
|
|
|
2400
2439
|
] }) })
|
|
2401
2440
|
] })
|
|
2402
2441
|
}
|
|
2403
|
-
),
|
|
2404
|
-
diagnostics && /* Open, and primary. This is the longest block on the tab and the obvious candidate
|
|
2405
|
-
for folding away — but the tab it sits on exists to answer "what should I fix
|
|
2406
|
-
before trusting any of this", and these checks ARE that answer. Folding it would
|
|
2407
|
-
have left Data health opening on a summary of the problem with the solution behind
|
|
2408
|
-
a click. It stays collapsible so a reader who has read it can get it out of the
|
|
2409
|
-
way. */
|
|
2410
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2411
|
-
Section,
|
|
2412
|
-
{
|
|
2413
|
-
title: "Configuration",
|
|
2414
|
-
subtitle: "What this site has wired up, and what it is missing.",
|
|
2415
|
-
collapsible: true,
|
|
2416
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(DiagnosticsPanel, { data: diagnostics })
|
|
2417
|
-
}
|
|
2418
2442
|
)
|
|
2419
2443
|
] });
|
|
2420
2444
|
}
|
|
@@ -2679,6 +2703,12 @@ function SegmentTable({ segments, dimension }) {
|
|
|
2679
2703
|
] }) })
|
|
2680
2704
|
] });
|
|
2681
2705
|
}
|
|
2706
|
+
function revenueCoversEveryOrder(data) {
|
|
2707
|
+
const counted = metricSortValue(data.orders);
|
|
2708
|
+
const withTotal = finiteOrNull(data.ordersWithTotal);
|
|
2709
|
+
if (counted === null || withTotal === null) return false;
|
|
2710
|
+
return counted === withTotal;
|
|
2711
|
+
}
|
|
2682
2712
|
function JourneyPanel({ data }) {
|
|
2683
2713
|
const segments = data.segments ?? [];
|
|
2684
2714
|
const allSteps = data.steps ?? [];
|