@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 CHANGED
@@ -2074,38 +2074,62 @@ function OverviewPanel({ data, previous, onBrush }) {
2074
2074
  source: "GA4",
2075
2075
  complete: true,
2076
2076
  unit: "percent",
2077
- // Fixed, not scaled to its own best day — otherwise a site at a flat 20%
2078
- // draws a full-height line and reads as healthy.
2079
- domain: [0, 1],
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 ? Math.min(1, d.ga4Pageviews / d.vercelPageviews) : null
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 ? Math.min(1, d.ga4Pageviews / d.vercelPageviews) : null
2097
+ value: d.vercelPageviews !== null && d.ga4Pageviews !== null && d.vercelPageviews > 0 ? d.ga4Pageviews / d.vercelPageviews : null
2089
2098
  }))
2090
2099
  }] : [],
2091
- ...data.crossSource?.some((d) => d.revenue !== null) ? [{
2092
- key: "revenue",
2093
- label: "Revenue",
2094
- source: "Sanity",
2095
- complete: true,
2096
- unit: "money",
2097
- // A sale is an event on a date, not a level that varies day to day.
2098
- mark: "events",
2099
- points: (data.crossSource ?? []).map((d) => ({ date: d.date, value: d.revenue }))
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
- /* @__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: [
2346
- 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` }),
2347
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 1, muted: true, children: data.interpretation })
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 ?? [];