@liiift-studio/sanity-visitor-insights 0.15.0 → 0.16.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 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, D as DiagnosticReport, J as JourneyData, c as MeasurementHealthData, T as TypefaceInterestData } from './ranges-BD8XH1Ef.mjs';
4
- export { C as CaptureBasis, d as CaptureEstimate, e as CaptureModel, f as CheckStatus, g as Coverage, h as DailyPoint, i as DateRange, j as DiagnosticCheck, E as EventCutover, k as JourneyOutcome, l as JourneyStep, L as LandingPage, P as PREEXISTING, m as REPORT_NAMES, n as ReportError, S as SiteAnalyticsConfig, o as SourceName, p as SourceRow, q as SourceStatus, r as TypefaceInterestRow, U as UnavailableReason, s as coverageForRange, t as estimated, u as isReportName, v as ok, w as partial, x as previousRange, y as resolveRange, z as unavailable, B as validateSiteConfig, F as valueOrNull } from './ranges-BD8XH1Ef.mjs';
3
+ import { R as ReportEnvelope, a as ReportName, b as RangeKey, M as MetricValue, A as AcquisitionData, D as DiagnosticReport, J as JourneyData, c as MeasurementHealthData, T as TypefaceInterestData } from './ranges-DvICo5H2.mjs';
4
+ export { C as CaptureBasis, d as CaptureEstimate, e as CaptureModel, f as CheckStatus, g as Coverage, h as DailyPoint, i as DateRange, j as DiagnosticCheck, E as EmailCampaign, k as EventCutover, l as JourneyOutcome, m as JourneyStep, L as LandingPage, P as PREEXISTING, n as REPORT_NAMES, o as ReportError, S as SiteAnalyticsConfig, p as SourceName, q as SourceRow, r as SourceStatus, s as TypefaceInterestRow, U as UnavailableReason, t as coverageForRange, u as estimated, v as isReportName, w as ok, x as partial, y as previousRange, z as resolveRange, B as unavailable, F as validateSiteConfig, G as valueOrNull } from './ranges-DvICo5H2.mjs';
5
5
 
6
6
  /**
7
7
  * The Visitor Insights Studio tool.
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, D as DiagnosticReport, J as JourneyData, c as MeasurementHealthData, T as TypefaceInterestData } from './ranges-BD8XH1Ef.js';
4
- export { C as CaptureBasis, d as CaptureEstimate, e as CaptureModel, f as CheckStatus, g as Coverage, h as DailyPoint, i as DateRange, j as DiagnosticCheck, E as EventCutover, k as JourneyOutcome, l as JourneyStep, L as LandingPage, P as PREEXISTING, m as REPORT_NAMES, n as ReportError, S as SiteAnalyticsConfig, o as SourceName, p as SourceRow, q as SourceStatus, r as TypefaceInterestRow, U as UnavailableReason, s as coverageForRange, t as estimated, u as isReportName, v as ok, w as partial, x as previousRange, y as resolveRange, z as unavailable, B as validateSiteConfig, F as valueOrNull } from './ranges-BD8XH1Ef.js';
3
+ import { R as ReportEnvelope, a as ReportName, b as RangeKey, M as MetricValue, A as AcquisitionData, D as DiagnosticReport, J as JourneyData, c as MeasurementHealthData, T as TypefaceInterestData } from './ranges-DvICo5H2.js';
4
+ export { C as CaptureBasis, d as CaptureEstimate, e as CaptureModel, f as CheckStatus, g as Coverage, h as DailyPoint, i as DateRange, j as DiagnosticCheck, E as EmailCampaign, k as EventCutover, l as JourneyOutcome, m as JourneyStep, L as LandingPage, P as PREEXISTING, n as REPORT_NAMES, o as ReportError, S as SiteAnalyticsConfig, p as SourceName, q as SourceRow, r as SourceStatus, s as TypefaceInterestRow, U as UnavailableReason, t as coverageForRange, u as estimated, v as isReportName, w as ok, x as partial, y as previousRange, z as resolveRange, B as unavailable, F as validateSiteConfig, G as valueOrNull } from './ranges-DvICo5H2.js';
5
5
 
6
6
  /**
7
7
  * The Visitor Insights Studio tool.
package/dist/index.js CHANGED
@@ -933,6 +933,43 @@ function MeasurementHealthPanel({ data, previous }) {
933
933
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(TrendChart, { points: data.daily ?? [] }),
934
934
  data.vercelDailyUnavailable && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Text, { size: 0, muted: true, children: "Vercel reports this range in weekly buckets, so only the GA4 line is plotted. Choose Week or Month to see both." })
935
935
  ] }),
936
+ (data.campaigns?.length ?? 0) > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_sanity_ui_compat2.Stack, { space: 3, children: [
937
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Heading, { size: 1, style: sectionHeading, children: "Email campaigns" }),
938
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Text, { size: 1, muted: true, children: "Clicks are distinct subscribers. Opens are inflated by Apple Mail Privacy Protection, which fetches images on the recipient\u2019s behalf \u2014 so sort on clicks, not opens." }),
939
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
940
+ SortableTable,
941
+ {
942
+ caption: "Email campaigns by clicks",
943
+ initialSort: "clicks",
944
+ rows: data.campaigns ?? [],
945
+ rowKey: (c) => `${c.sentAt}-${c.title}`,
946
+ filterOn: (c) => `${c.title} ${c.subject}`,
947
+ filterPlaceholder: "Filter campaigns",
948
+ exportName: "email-campaigns",
949
+ columns: [
950
+ {
951
+ key: "title",
952
+ label: "Campaign",
953
+ sortValue: (c) => c.title,
954
+ render: (c) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_sanity_ui_compat2.Stack, { space: 1, children: [
955
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Text, { size: 1, children: c.title }),
956
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Text, { size: 0, muted: true, children: c.sentAt.slice(0, 10) })
957
+ ] })
958
+ },
959
+ { key: "sent", label: "Sent", numeric: true, sortValue: (c) => c.sent, render: (c) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Text, { size: 1, children: formatCount(c.sent) }) },
960
+ { key: "opens", label: "Opens", numeric: true, sortValue: (c) => c.opens, render: (c) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Text, { size: 1, muted: true, children: formatCount(c.opens) }) },
961
+ { key: "clicks", label: "Clicks", numeric: true, sortValue: (c) => c.clicks, render: (c) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Text, { size: 1, children: formatCount(c.clicks) }) },
962
+ {
963
+ key: "unsub",
964
+ label: "Unsubscribed",
965
+ numeric: true,
966
+ sortValue: (c) => c.unsubscribed,
967
+ render: (c) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Text, { size: 1, muted: true, children: formatCount(c.unsubscribed) })
968
+ }
969
+ ]
970
+ }
971
+ )
972
+ ] }),
936
973
  Object.keys(data.orderStatuses ?? {}).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_sanity_ui_compat2.Stack, { space: 3, children: [
937
974
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Heading, { size: 1, style: sectionHeading, children: "Order statuses in this range" }),
938
975
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Text, { size: 1, muted: true, children: "What the orders actually say, before any filtering. Use these values to set which statuses count as a sale." }),
@@ -945,6 +982,20 @@ function MeasurementHealthPanel({ data, previous }) {
945
982
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Heading, { size: 1, style: sectionHeading, children: "Context" }),
946
983
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Text, { size: 1, muted: true, children: "Different units to the figures above, and to each other. Shown for scale, never differenced." }),
947
984
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: cardGrid, children: [
985
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Card, { padding: 3, radius: 2, tone: "transparent", border: true, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_sanity_ui_compat2.Stack, { space: 3, children: [
986
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Label, { size: 1, muted: true, children: "Mailing list" }),
987
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: figureRow, children: [
988
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(MetricFigure, { metric: metricOr(data.audience, OLDER_ROUTE), label: "Mailing list members" }),
989
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
990
+ Delta,
991
+ {
992
+ current: metricSortValue(data.audience),
993
+ previous: metricSortValue(previous?.audience)
994
+ }
995
+ )
996
+ ] }),
997
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Text, { size: 0, muted: true, children: "Mailchimp\u2019s own count. Not consent-gated or blockable, so it replaces the site\u2019s subscribe event rather than sitting beside it." })
998
+ ] }) }),
948
999
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Card, { padding: 3, radius: 2, tone: "transparent", border: true, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_sanity_ui_compat2.Stack, { space: 3, children: [
949
1000
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Label, { size: 1, muted: true, children: "Revenue" }),
950
1001
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: figureRow, children: [
@@ -1486,7 +1537,8 @@ function RangeSelector({
1486
1537
  var SOURCE_LABEL = {
1487
1538
  ga4: "Google Analytics",
1488
1539
  vercel: "Vercel",
1489
- sanity: "Orders"
1540
+ sanity: "Orders",
1541
+ mailchimp: "Mailchimp"
1490
1542
  };
1491
1543
  function SourceStatusRow({ sources }) {
1492
1544
  const degraded = Object.entries(sources).filter(([, s]) => s.status !== "ok");