@liiift-studio/sanity-visitor-insights 0.76.0 → 0.77.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 +99 -80
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +99 -80
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/studio/CrossSourceTimeline.tsx +3 -3
- package/src/studio/Figure.tsx +69 -15
- package/src/studio/panels.test.tsx +172 -3
- package/src/studio/panels.tsx +139 -121
- package/src/studio/useReport.ts +8 -1
package/dist/index.js
CHANGED
|
@@ -165,7 +165,7 @@ function useReport({ apiBaseUrl, report, range, custom, compare, enabled = true
|
|
|
165
165
|
}
|
|
166
166
|
void run();
|
|
167
167
|
return () => controller.abort();
|
|
168
|
-
}, [client, apiBaseUrl, report, range, custom?.start, custom?.end, nonce, enabled]);
|
|
168
|
+
}, [client, apiBaseUrl, report, range, custom?.start, custom?.end, compare, nonce, enabled]);
|
|
169
169
|
return { state, reload };
|
|
170
170
|
}
|
|
171
171
|
|
|
@@ -370,6 +370,11 @@ function isReportName(value) {
|
|
|
370
370
|
|
|
371
371
|
// src/studio/Figure.tsx
|
|
372
372
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
373
|
+
var SPACE = { pair: 4, block: 8, group: 20, section: 40 };
|
|
374
|
+
var stackPair = { display: "grid", gap: SPACE.pair };
|
|
375
|
+
var stackBlock = { display: "grid", gap: SPACE.block };
|
|
376
|
+
var stackGroup = { display: "grid", gap: SPACE.group };
|
|
377
|
+
var panelStack = { display: "grid", gap: SPACE.section };
|
|
373
378
|
var REASON_TEXT = {
|
|
374
379
|
not_instrumented: "Not tracked on this site",
|
|
375
380
|
before_cutover: "Not tracked during this period",
|
|
@@ -813,11 +818,11 @@ function gapLabel(delta, measurement, entry = 0) {
|
|
|
813
818
|
return `${formatCount(-delta)} more \u2014 not a subset of the step above`;
|
|
814
819
|
}
|
|
815
820
|
var partialSlot = { height: 10 };
|
|
816
|
-
var funnelSegmentKey = { display: "flex", gap:
|
|
821
|
+
var funnelSegmentKey = { display: "flex", gap: SPACE.group, flexWrap: "wrap", paddingTop: SPACE.pair };
|
|
817
822
|
var ladderRow = {
|
|
818
823
|
display: "grid",
|
|
819
824
|
gridTemplateColumns: "minmax(80px, 1.1fr) minmax(60px, 0.8fr) minmax(60px, 2fr) auto",
|
|
820
|
-
gap:
|
|
825
|
+
gap: SPACE.block,
|
|
821
826
|
alignItems: "center"
|
|
822
827
|
};
|
|
823
828
|
var ladderTrack = {
|
|
@@ -941,7 +946,7 @@ function Section({
|
|
|
941
946
|
const [open, setOpen] = import_react2.default.useState(defaultOpen);
|
|
942
947
|
const bodyId = import_react2.default.useId();
|
|
943
948
|
const shown = !collapsible || open;
|
|
944
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.
|
|
949
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { style: sectionBox, children: [
|
|
945
950
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: sectionHeader, children: [
|
|
946
951
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_sanity_ui_compat.Stack, { space: 1, children: [
|
|
947
952
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_sanity_ui_compat.Heading, { size: tone === "primary" ? 1 : 0, style: tone === "primary" ? primaryTitle : secondaryTitle, children: title }),
|
|
@@ -959,8 +964,8 @@ function Section({
|
|
|
959
964
|
}
|
|
960
965
|
)
|
|
961
966
|
] }),
|
|
962
|
-
shown && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { id: bodyId, children })
|
|
963
|
-
] })
|
|
967
|
+
shown && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { id: bodyId, style: sectionBody, children })
|
|
968
|
+
] });
|
|
964
969
|
}
|
|
965
970
|
function SectionTitle({
|
|
966
971
|
title,
|
|
@@ -1232,7 +1237,7 @@ function SortableTable({
|
|
|
1232
1237
|
),
|
|
1233
1238
|
exportName && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: tableControlButton, onClick: () => void copyCsv(), children: copied === "done" ? "Copied" : copied === "failed" ? "Could not copy" : "Copy as CSV" })
|
|
1234
1239
|
] }),
|
|
1235
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_sanity_ui_compat.Card, { radius: 2, tone: "transparent",
|
|
1240
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_sanity_ui_compat.Card, { radius: 2, tone: "transparent", style: tableWrapper, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { style: tableBase, children: [
|
|
1236
1241
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("caption", { style: visuallyHidden, children: caption }),
|
|
1237
1242
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tr", { children: shown.map((column) => {
|
|
1238
1243
|
const isActive = sort?.key === column.key;
|
|
@@ -1290,15 +1295,20 @@ function csvCell(cell) {
|
|
|
1290
1295
|
var tableControls = {
|
|
1291
1296
|
display: "flex",
|
|
1292
1297
|
alignItems: "center",
|
|
1293
|
-
gap:
|
|
1298
|
+
gap: SPACE.block,
|
|
1294
1299
|
flexWrap: "wrap"
|
|
1295
1300
|
};
|
|
1301
|
+
var sectionBox = { display: "grid", gap: SPACE.group };
|
|
1302
|
+
var sectionBody = { display: "grid", gap: SPACE.group };
|
|
1296
1303
|
var sectionHeader = {
|
|
1297
1304
|
display: "flex",
|
|
1298
1305
|
alignItems: "flex-start",
|
|
1299
1306
|
justifyContent: "space-between",
|
|
1300
1307
|
gap: 12,
|
|
1301
|
-
|
|
1308
|
+
// 0.35, not 0.22. This rule was the faintest line in the file and the only thing separating one
|
|
1309
|
+
// section from the next — while every button drew at 0.30. A "Hide" control outranking the
|
|
1310
|
+
// boundary between two regions of the panel is the hierarchy upside down.
|
|
1311
|
+
borderBottom: "1px solid var(--card-border-color, rgba(128,128,128,0.35))",
|
|
1302
1312
|
paddingBottom: 6
|
|
1303
1313
|
};
|
|
1304
1314
|
var primaryTitle = { margin: 0, lineHeight: 1.3 };
|
|
@@ -1312,7 +1322,7 @@ var secondaryTitle = {
|
|
|
1312
1322
|
var sectionToggle = {
|
|
1313
1323
|
appearance: "none",
|
|
1314
1324
|
background: "transparent",
|
|
1315
|
-
border: "1px solid var(--card-border-color, rgba(128,128,128,0.
|
|
1325
|
+
border: "1px solid var(--card-border-color, rgba(128,128,128,0.22))",
|
|
1316
1326
|
borderRadius: 3,
|
|
1317
1327
|
color: "inherit",
|
|
1318
1328
|
font: "inherit",
|
|
@@ -1360,13 +1370,13 @@ var estimateDot = {
|
|
|
1360
1370
|
var ratioRow = {
|
|
1361
1371
|
display: "flex",
|
|
1362
1372
|
alignItems: "baseline",
|
|
1363
|
-
gap:
|
|
1373
|
+
gap: SPACE.block,
|
|
1364
1374
|
flexWrap: "wrap"
|
|
1365
1375
|
};
|
|
1366
1376
|
var ratioToggle = {
|
|
1367
1377
|
appearance: "none",
|
|
1368
1378
|
background: "transparent",
|
|
1369
|
-
border: "1px solid var(--card-border-color, rgba(128,128,128,0.
|
|
1379
|
+
border: "1px solid var(--card-border-color, rgba(128,128,128,0.22))",
|
|
1370
1380
|
borderRadius: 3,
|
|
1371
1381
|
color: "inherit",
|
|
1372
1382
|
font: "inherit",
|
|
@@ -1380,7 +1390,7 @@ var filterInput = {
|
|
|
1380
1390
|
fontSize: "0.85em",
|
|
1381
1391
|
padding: "4px 8px",
|
|
1382
1392
|
borderRadius: 3,
|
|
1383
|
-
border: "1px solid var(--card-border-color, rgba(128,128,128,0.
|
|
1393
|
+
border: "1px solid var(--card-border-color, rgba(128,128,128,0.22))",
|
|
1384
1394
|
background: "transparent",
|
|
1385
1395
|
color: "inherit",
|
|
1386
1396
|
minWidth: 160
|
|
@@ -1388,7 +1398,7 @@ var filterInput = {
|
|
|
1388
1398
|
var tableControlButton = {
|
|
1389
1399
|
appearance: "none",
|
|
1390
1400
|
background: "transparent",
|
|
1391
|
-
border: "1px solid var(--card-border-color, rgba(128,128,128,0.
|
|
1401
|
+
border: "1px solid var(--card-border-color, rgba(128,128,128,0.22))",
|
|
1392
1402
|
borderRadius: 3,
|
|
1393
1403
|
color: "inherit",
|
|
1394
1404
|
font: "inherit",
|
|
@@ -1433,7 +1443,7 @@ var tableBase = { width: "100%", borderCollapse: "collapse", minWidth: 420 };
|
|
|
1433
1443
|
var headCell = {
|
|
1434
1444
|
padding: 0,
|
|
1435
1445
|
textAlign: "left",
|
|
1436
|
-
borderBottom: "1px solid var(--card-border-color, rgba(128,128,128,0.
|
|
1446
|
+
borderBottom: "1px solid var(--card-border-color, rgba(128,128,128,0.22))",
|
|
1437
1447
|
whiteSpace: "nowrap"
|
|
1438
1448
|
};
|
|
1439
1449
|
var headCellNumeric = { ...headCell, textAlign: "right" };
|
|
@@ -2118,14 +2128,14 @@ function shortfallLabel(series) {
|
|
|
2118
2128
|
var frameStyle = { width: "100%", overflow: "hidden", position: "relative" };
|
|
2119
2129
|
var readoutRow = {
|
|
2120
2130
|
display: "flex",
|
|
2121
|
-
gap:
|
|
2131
|
+
gap: SPACE.block,
|
|
2122
2132
|
flexWrap: "wrap",
|
|
2123
2133
|
alignItems: "baseline",
|
|
2124
2134
|
minHeight: 54
|
|
2125
2135
|
};
|
|
2126
2136
|
var legendRow = {
|
|
2127
2137
|
display: "flex",
|
|
2128
|
-
gap:
|
|
2138
|
+
gap: SPACE.block,
|
|
2129
2139
|
flexWrap: "wrap",
|
|
2130
2140
|
alignItems: "center"
|
|
2131
2141
|
};
|
|
@@ -2186,7 +2196,7 @@ function acquisitionRowKey(row) {
|
|
|
2186
2196
|
var figureRow = {
|
|
2187
2197
|
display: "flex",
|
|
2188
2198
|
alignItems: "baseline",
|
|
2189
|
-
gap:
|
|
2199
|
+
gap: SPACE.block,
|
|
2190
2200
|
flexWrap: "wrap"
|
|
2191
2201
|
};
|
|
2192
2202
|
var sourceLink = {
|
|
@@ -2201,7 +2211,7 @@ function isLinkableHost(source) {
|
|
|
2201
2211
|
var cardGrid = {
|
|
2202
2212
|
display: "grid",
|
|
2203
2213
|
gridTemplateColumns: "repeat(auto-fit, minmax(min(14rem, 100%), 1fr))",
|
|
2204
|
-
gap:
|
|
2214
|
+
gap: SPACE.group
|
|
2205
2215
|
};
|
|
2206
2216
|
function gapOf(day) {
|
|
2207
2217
|
if (day.vercelPageviews === null || day.ga4Pageviews === null) return null;
|
|
@@ -2212,10 +2222,10 @@ function coverageOf(day) {
|
|
|
2212
2222
|
return day.ga4Pageviews / day.vercelPageviews;
|
|
2213
2223
|
}
|
|
2214
2224
|
function OverviewPanel({ data, previous, onBrush }) {
|
|
2215
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2225
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: panelStack, children: [
|
|
2216
2226
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Verdict, { data, previous }),
|
|
2217
2227
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: cardGrid, children: [
|
|
2218
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent",
|
|
2228
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: stackBlock, children: [
|
|
2219
2229
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Label, { size: 1, muted: true, children: "Revenue" }),
|
|
2220
2230
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: figureRow, children: [
|
|
2221
2231
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
@@ -2231,7 +2241,7 @@ function OverviewPanel({ data, previous, onBrush }) {
|
|
|
2231
2241
|
] }),
|
|
2232
2242
|
revenueCoversEveryOrder(data) && rankLine(data.crossSource, (d) => d.revenue) && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 0, muted: true, children: rankLine(data.crossSource, (d) => d.revenue) })
|
|
2233
2243
|
] }) }),
|
|
2234
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent",
|
|
2244
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: stackBlock, children: [
|
|
2235
2245
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Label, { size: 1, muted: true, children: "Orders" }),
|
|
2236
2246
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: figureRow, children: [
|
|
2237
2247
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MetricFigure, { metric: metricOr(data.orders, OLDER_ROUTE), label: "Orders" }),
|
|
@@ -2239,7 +2249,7 @@ function OverviewPanel({ data, previous, onBrush }) {
|
|
|
2239
2249
|
] }),
|
|
2240
2250
|
rankLine(data.crossSource, (d) => d.orders) && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 0, muted: true, children: rankLine(data.crossSource, (d) => d.orders) })
|
|
2241
2251
|
] }) }),
|
|
2242
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent",
|
|
2252
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: stackBlock, children: [
|
|
2243
2253
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Label, { size: 1, muted: true, children: "Traffic" }),
|
|
2244
2254
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: figureRow, children: [
|
|
2245
2255
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MetricFigure, { metric: metricOr(data.vercelPageviews, OLDER_ROUTE), label: "Pageviews" }),
|
|
@@ -2247,7 +2257,7 @@ function OverviewPanel({ data, previous, onBrush }) {
|
|
|
2247
2257
|
] }),
|
|
2248
2258
|
data.vercelPageviews && data.vercelPageviews.status !== "unavailable" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 0, muted: true, children: "Pageviews, from Vercel\u2019s own counter." })
|
|
2249
2259
|
] }) }),
|
|
2250
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent",
|
|
2260
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: stackBlock, children: [
|
|
2251
2261
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Label, { size: 1, muted: true, children: "Mailing list, total" }),
|
|
2252
2262
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: figureRow, children: [
|
|
2253
2263
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MetricFigure, { metric: metricOr(data.audience, OLDER_ROUTE), label: "Mailing list members" }),
|
|
@@ -2268,7 +2278,7 @@ function OverviewPanel({ data, previous, onBrush }) {
|
|
|
2268
2278
|
] }) })
|
|
2269
2279
|
] }),
|
|
2270
2280
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: cardGrid, children: [
|
|
2271
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent",
|
|
2281
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: stackBlock, children: [
|
|
2272
2282
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Label, { size: 1, muted: true, children: "Average order" }),
|
|
2273
2283
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2274
2284
|
RatioFigure,
|
|
@@ -2285,7 +2295,7 @@ function OverviewPanel({ data, previous, onBrush }) {
|
|
|
2285
2295
|
averageOrderValue(data).status === "partial" && averageOrderValue(data).note && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 0, muted: true, children: averageOrderValue(data).note }),
|
|
2286
2296
|
averageOrderValue(data).status === "ok" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 0, muted: true, children: "From your orders, so exact." })
|
|
2287
2297
|
] }) }),
|
|
2288
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent",
|
|
2298
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: stackBlock, children: [
|
|
2289
2299
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Label, { size: 1, muted: true, children: "Visitors per order" }),
|
|
2290
2300
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2291
2301
|
RatioFigure,
|
|
@@ -2302,7 +2312,7 @@ function OverviewPanel({ data, previous, onBrush }) {
|
|
|
2302
2312
|
data.vercelVisitors && data.vercelVisitors.status !== "unavailable" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 0, muted: true, children: "Vercel\u2019s visitor count. A ceiling \u2014 some are bots or the same person twice." })
|
|
2303
2313
|
] }) })
|
|
2304
2314
|
] }),
|
|
2305
|
-
(data.crossSource?.length ?? 0) >= 3 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2315
|
+
(data.crossSource?.length ?? 0) >= 3 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: stackBlock, children: [
|
|
2306
2316
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SectionTitle, { title: "Everything, on one time axis" }),
|
|
2307
2317
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 1, muted: true, children: "Each row has its own scale, so the rows cannot be compared by height \u2014 only by shape." }),
|
|
2308
2318
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
@@ -2509,7 +2519,7 @@ function OverviewPanel({ data, previous, onBrush }) {
|
|
|
2509
2519
|
}
|
|
2510
2520
|
)
|
|
2511
2521
|
] }),
|
|
2512
|
-
(data.campaigns?.length ?? 0) > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2522
|
+
(data.campaigns?.length ?? 0) > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: stackBlock, children: [
|
|
2513
2523
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SectionTitle, { title: "Email campaigns" }),
|
|
2514
2524
|
/* @__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." }),
|
|
2515
2525
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_sanity_ui_compat3.Text, { size: 1, muted: true, children: [
|
|
@@ -2615,7 +2625,7 @@ function Verdict({ data, previous }) {
|
|
|
2615
2625
|
const seeing = shortfall !== null && shortfall !== void 0 ? `GA4 is seeing ${formatPercent(1 - shortfall, 0)} of your traffic` : null;
|
|
2616
2626
|
const broken = shortfall === null || shortfall === void 0 ? data.capture?.discrepancy ? "measurement disagrees between sources" : null : shortfall > 0.6 ? `${seeing} \u2014 treat its figures as broken` : shortfall > 0.35 ? `${seeing} \u2014 its figures are undercounts, not what happened` : data.capture?.discrepancy ? "measurement disagrees between sources" : null;
|
|
2617
2627
|
if (parts.length === 0 && !broken) {
|
|
2618
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent",
|
|
2628
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent", style: { borderLeftWidth: 3, borderLeftStyle: "solid" }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 4, children: "No figures arrived for this window." }) });
|
|
2619
2629
|
}
|
|
2620
2630
|
const noticeable = shortfall !== null && shortfall !== void 0 && shortfall > 0.2;
|
|
2621
2631
|
const closing = broken || !noticeable ? "" : ` \xB7 ${seeing}`;
|
|
@@ -2628,7 +2638,7 @@ function Verdict({ data, previous }) {
|
|
|
2628
2638
|
border: true,
|
|
2629
2639
|
style: broken ? { borderLeftWidth: 3, borderLeftStyle: "solid" } : void 0,
|
|
2630
2640
|
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_sanity_ui_compat3.Stack, { space: 2, children: [
|
|
2631
|
-
parts.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_sanity_ui_compat3.Text, { size:
|
|
2641
|
+
parts.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_sanity_ui_compat3.Text, { size: 4, weight: broken ? "semibold" : "medium", children: [
|
|
2632
2642
|
parts.join(" \xB7 "),
|
|
2633
2643
|
closing
|
|
2634
2644
|
] }),
|
|
@@ -2639,12 +2649,12 @@ function Verdict({ data, previous }) {
|
|
|
2639
2649
|
}
|
|
2640
2650
|
function DataHealthPanel({ data, diagnostics }) {
|
|
2641
2651
|
const contained = isContainment(data.vercelPageviews, data.ga4Pageviews);
|
|
2642
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2643
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent",
|
|
2652
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: panelStack, children: [
|
|
2653
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_sanity_ui_compat3.Stack, { space: 2, children: [
|
|
2644
2654
|
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` }),
|
|
2645
2655
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 1, muted: true, children: data.interpretation })
|
|
2646
2656
|
] }) }),
|
|
2647
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2657
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: stackBlock, children: [
|
|
2648
2658
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SectionTitle, { title: "Pageviews, source against source" }),
|
|
2649
2659
|
/* @__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." }),
|
|
2650
2660
|
contained ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
@@ -2683,7 +2693,7 @@ function DataHealthPanel({ data, diagnostics }) {
|
|
|
2683
2693
|
return null and the section rendered NOTHING — not even the figure Vercel did
|
|
2684
2694
|
report. That is the state where the reader most needs to see what survived, and
|
|
2685
2695
|
it is the one the card below spends a comment explaining. */
|
|
2686
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2696
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: stackBlock, children: [
|
|
2687
2697
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: figureRow, children: [
|
|
2688
2698
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Label, { size: 1, muted: true, children: "Pageviews Vercel counted" }),
|
|
2689
2699
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MetricFigure, { metric: metricOr(data.vercelPageviews, OLDER_ROUTE), label: "Vercel pageviews", size: 3 })
|
|
@@ -2711,7 +2721,7 @@ function DataHealthPanel({ data, diagnostics }) {
|
|
|
2711
2721
|
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(DiagnosticsPanel, { data: diagnostics })
|
|
2712
2722
|
}
|
|
2713
2723
|
),
|
|
2714
|
-
((data.capture?.estimates?.length ?? 0) > 0 || data.estimatedSessions?.status === "estimated") && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2724
|
+
((data.capture?.estimates?.length ?? 0) > 0 || data.estimatedSessions?.status === "estimated") && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: stackBlock, children: [
|
|
2715
2725
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SectionTitle, { title: "How much GA4 is seeing" }),
|
|
2716
2726
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2717
2727
|
EstimateDotPlot,
|
|
@@ -2725,27 +2735,33 @@ function DataHealthPanel({ data, diagnostics }) {
|
|
|
2725
2735
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 1, weight: "medium", children: "The sources disagree, and that is informative" }),
|
|
2726
2736
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 1, children: data.capture.discrepancy })
|
|
2727
2737
|
] }) }),
|
|
2728
|
-
data.estimatedSessions && data.estimatedSessions.status === "estimated" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent",
|
|
2738
|
+
data.estimatedSessions && data.estimatedSessions.status === "estimated" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: stackBlock, children: [
|
|
2729
2739
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Label, { size: 1, muted: true, children: "Sessions, corrected for what GA4 misses" }),
|
|
2730
2740
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MetricFigure, { metric: metricOr(data.estimatedSessions, OLDER_ROUTE), label: "Estimated sessions" })
|
|
2731
2741
|
] }) })
|
|
2732
2742
|
] }),
|
|
2733
|
-
Object.keys(data.orderStatuses ?? {}).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2743
|
+
Object.keys(data.orderStatuses ?? {}).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2744
|
+
Section,
|
|
2745
|
+
{
|
|
2746
|
+
title: "Order statuses in this range",
|
|
2747
|
+
tone: "secondary",
|
|
2748
|
+
subtitle: "What the orders actually say, before any filtering. Use these values to set which statuses count as a sale.",
|
|
2749
|
+
collapsible: true,
|
|
2750
|
+
defaultOpen: false,
|
|
2751
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2752
|
+
ProportionChart,
|
|
2753
|
+
{
|
|
2754
|
+
bars: Object.entries(data.orderStatuses ?? {}).map(([status, count]) => ({
|
|
2755
|
+
key: status,
|
|
2756
|
+
label: status,
|
|
2757
|
+
value: count
|
|
2758
|
+
})),
|
|
2759
|
+
format: (n) => formatCount(n),
|
|
2760
|
+
totalLabel: "Orders in this range"
|
|
2761
|
+
}
|
|
2762
|
+
)
|
|
2763
|
+
}
|
|
2764
|
+
),
|
|
2749
2765
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2750
2766
|
Section,
|
|
2751
2767
|
{
|
|
@@ -2753,17 +2769,18 @@ function DataHealthPanel({ data, diagnostics }) {
|
|
|
2753
2769
|
tone: "secondary",
|
|
2754
2770
|
subtitle: "Different units to the figures above, and to each other.",
|
|
2755
2771
|
collapsible: true,
|
|
2772
|
+
defaultOpen: false,
|
|
2756
2773
|
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: cardGrid, children: [
|
|
2757
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent",
|
|
2774
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: stackBlock, children: [
|
|
2758
2775
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Label, { size: 1, muted: true, children: "Vercel visitors" }),
|
|
2759
2776
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MetricFigure, { metric: metricOr(data.vercelVisitors, OLDER_ROUTE), label: "Vercel visitors" }),
|
|
2760
2777
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 0, muted: true, children: "Vercel\u2019s own counter. Blocked far less often than Google Analytics, but not never \u2014 so read it as a floor on your real traffic." })
|
|
2761
2778
|
] }) }),
|
|
2762
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent",
|
|
2779
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: stackBlock, children: [
|
|
2763
2780
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Label, { size: 1, muted: true, children: "GA4 sessions" }),
|
|
2764
2781
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MetricFigure, { metric: metricOr(data.ga4Sessions, OLDER_ROUTE), label: "GA4 sessions" })
|
|
2765
2782
|
] }) }),
|
|
2766
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent",
|
|
2783
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: stackBlock, children: [
|
|
2767
2784
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Label, { size: 1, muted: true, children: "Consent granted" }),
|
|
2768
2785
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MetricFigure, { metric: metricOr(data.consentRate, OLDER_ROUTE), label: "Consent granted, share of visitors GA4 saw", unit: "percent" })
|
|
2769
2786
|
] }) })
|
|
@@ -2776,16 +2793,16 @@ function AcquisitionPanel({ data, previous }) {
|
|
|
2776
2793
|
const designShare = finiteOrNull(data.designIndustryShare);
|
|
2777
2794
|
const unattributedShare = finiteOrNull(data.unattributedShare);
|
|
2778
2795
|
const sessions = finiteOrNull(data.totalSessions);
|
|
2779
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2796
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: panelStack, children: [
|
|
2780
2797
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: cardGrid, children: [
|
|
2781
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent",
|
|
2798
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: stackBlock, children: [
|
|
2782
2799
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Label, { size: 1, muted: true, children: "Sessions" }),
|
|
2783
2800
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: figureRow, children: [
|
|
2784
2801
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 4, children: sessions === null ? "\u2014" : formatCount(sessions) }),
|
|
2785
2802
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Delta, { current: sessions, previous: finiteOrNull(previous?.totalSessions) })
|
|
2786
2803
|
] })
|
|
2787
2804
|
] }) }),
|
|
2788
|
-
designShare !== null && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent",
|
|
2805
|
+
designShare !== null && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: stackBlock, children: [
|
|
2789
2806
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Label, { size: 1, muted: true, children: "From design-industry referrers" }),
|
|
2790
2807
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: figureRow, children: [
|
|
2791
2808
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_sanity_ui_compat3.Text, { size: 4, children: [
|
|
@@ -2806,7 +2823,7 @@ function AcquisitionPanel({ data, previous }) {
|
|
|
2806
2823
|
data.rowsTruncated && " GA4 held more sources than are listed here, so the real share is higher."
|
|
2807
2824
|
] })
|
|
2808
2825
|
] }) }),
|
|
2809
|
-
unattributedShare !== null && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent",
|
|
2826
|
+
unattributedShare !== null && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: stackBlock, children: [
|
|
2810
2827
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Label, { size: 1, muted: true, children: "No source" }),
|
|
2811
2828
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: figureRow, children: [
|
|
2812
2829
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 4, children: formatPercent(unattributedShare, 1) }),
|
|
@@ -2823,7 +2840,7 @@ function AcquisitionPanel({ data, previous }) {
|
|
|
2823
2840
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 0, muted: true, children: "Direct visits plus rows GA4 could not attribute." })
|
|
2824
2841
|
] }) })
|
|
2825
2842
|
] }),
|
|
2826
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2843
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: stackBlock, children: [
|
|
2827
2844
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SectionTitle, { title: "Traffic sources" }),
|
|
2828
2845
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 1, muted: true, children: "Sort or filter to find a source. Excluding a row hides it from this table." }),
|
|
2829
2846
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
@@ -3031,7 +3048,7 @@ function JourneyPanel({ data }) {
|
|
|
3031
3048
|
}]
|
|
3032
3049
|
);
|
|
3033
3050
|
const tracked = data.measurement === "sequence";
|
|
3034
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
3051
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: panelStack, children: [
|
|
3035
3052
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: tracked ? "transparent" : "caution", border: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_sanity_ui_compat3.Stack, { space: 2, children: [
|
|
3036
3053
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 1, weight: "medium", children: tracked ? "Tracked path" : "Not a tracked path" }),
|
|
3037
3054
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 1, muted: tracked, children: data.approximationNote })
|
|
@@ -3076,7 +3093,7 @@ function JourneyPanel({ data }) {
|
|
|
3076
3093
|
{
|
|
3077
3094
|
title: "Other outcomes",
|
|
3078
3095
|
subtitle: "Successful outcomes that are not a licence sale, counted over the same window as the funnel but not a step within it.",
|
|
3079
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: cardGrid, children: (data.outcomes ?? []).map((outcome) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent",
|
|
3096
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: cardGrid, children: (data.outcomes ?? []).map((outcome) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: stackBlock, children: [
|
|
3080
3097
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Label, { size: 1, muted: true, children: outcome.label }),
|
|
3081
3098
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MetricFigure, { metric: outcome.count, label: outcome.label, size: 4 }),
|
|
3082
3099
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 0, muted: true, children: outcome.note })
|
|
@@ -3192,9 +3209,9 @@ function visitorsPerOrder(data) {
|
|
|
3192
3209
|
}
|
|
3193
3210
|
function TypefaceInterestPanel({ data }) {
|
|
3194
3211
|
const benchmark = catalogueRate(data.rows ?? []);
|
|
3195
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
3196
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent",
|
|
3197
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
3212
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: panelStack, children: [
|
|
3213
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 1, muted: true, children: data.interpretationNote }) }),
|
|
3214
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: stackBlock, children: [
|
|
3198
3215
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SectionTitle, { title: "Engagement by typeface" }),
|
|
3199
3216
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_sanity_ui_compat3.Text, { size: 1, muted: true, children: [
|
|
3200
3217
|
"Sort by any column. \u201CSells vs catalogue\u201D compares each family\u2019s sales-per-view against the catalogue as a whole \u2014 1.0\xD7 is average, and sorting up finds the families that are looked at and do not sell. It is a comparison between your families, not the share of visitors who buy: Google Analytics sees only a fraction of the views, which moves every family together and so cancels out here. With one or two sales a family will still swing a long way, so read it alongside the order counts beside it.",
|
|
@@ -3332,23 +3349,25 @@ function TypefaceInterestPanel({ data }) {
|
|
|
3332
3349
|
}
|
|
3333
3350
|
)
|
|
3334
3351
|
] }),
|
|
3335
|
-
(data.licences?.length ?? 0) > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
3352
|
+
(data.licences?.length ?? 0) > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: stackBlock, children: [
|
|
3336
3353
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SectionTitle, { title: "How licences sell" }),
|
|
3337
3354
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 1, muted: true, children: "From your orders, so exact. Bars are orders; the money beside them is that order total split evenly across the licences on it, so it is a share rather than a price." }),
|
|
3338
3355
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LicenceLadder, { rows: data.licences ?? [], currency: data.currency ?? null })
|
|
3339
3356
|
] }),
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3357
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: stackBlock, children: [
|
|
3358
|
+
data.revenueIsApportioned && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 0, muted: true, children: "An order covering several families is split evenly between them, because the order documents carry no per-line value." }),
|
|
3359
|
+
finiteOrNull(data.unattributedRevenue) !== null && data.unattributedRevenue > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_sanity_ui_compat3.Text, { size: 0, muted: true, children: [
|
|
3360
|
+
formatMoney(data.unattributedRevenue, data.currency ?? null),
|
|
3361
|
+
" of this range\u2019s takings is not in the column above \u2014 those orders name no family in this catalogue."
|
|
3362
|
+
] }),
|
|
3363
|
+
finiteOrNull(data.ordersMissingTotal) !== null && data.ordersMissingTotal > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_sanity_ui_compat3.Text, { size: 0, muted: true, children: [
|
|
3364
|
+
formatCount(data.ordersMissingTotal),
|
|
3365
|
+
" order",
|
|
3366
|
+
data.ordersMissingTotal === 1 ? "" : "s",
|
|
3367
|
+
" in this range carry no amount, so the revenue column does not cover ",
|
|
3368
|
+
data.ordersMissingTotal === 1 ? "it" : "them",
|
|
3369
|
+
"."
|
|
3370
|
+
] })
|
|
3352
3371
|
] })
|
|
3353
3372
|
] });
|
|
3354
3373
|
}
|
|
@@ -3369,9 +3388,9 @@ function DiagnosticsPanel({ data }) {
|
|
|
3369
3388
|
const failing = checks.filter((c) => c.status === "fail").length;
|
|
3370
3389
|
const warning = checks.filter((c) => c.status === "warn").length;
|
|
3371
3390
|
const summary = checks.length === 0 ? "No checks ran. Nothing here has been verified either way." : data.verdict === "pass" ? "Configuration and credentials check out. That covers the wiring, not whether the figures are worth trusting \u2014 the caveats on each panel still apply." : failing === 0 && warning === 0 ? `Nothing is failing. ${checks.length - failing - warning} check${checks.length - failing - warning === 1 ? "" : "s"} could not run in this range \u2014 usually because there was nothing to check, not because something is wrong.` : `${failing} failing, ${warning} worth a look. Panels depending on these will be wrong or incomplete until they are resolved.`;
|
|
3372
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
3391
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: panelStack, children: [
|
|
3373
3392
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: CHECK_TONE[data.verdict] ?? "default", border: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 1, children: summary }) }),
|
|
3374
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3393
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: stackBlock, children: checks.map((item) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: stackBlock, children: [
|
|
3375
3394
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_sanity_ui_compat3.Flex, { align: "center", justify: "space-between", gap: 3, children: [
|
|
3376
3395
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 1, weight: "semibold", children: item.label }),
|
|
3377
3396
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Badge, { tone: CHECK_TONE[item.status] ?? "default", fontSize: 0, children: CHECK_WORD[item.status] ?? item.status })
|