PageSourceSearch

https://nelsonremediation.com/assets/AdminPfasCluster-BJZ__61Z.js

js nelsonremediation.com collected 2026-10-09 23:06:51 UTC 8,838 bytes, 1 lines download raw bytes

1import{r as u,j as e}from"./vendor-react-ChCU2QM8.js";import{L as F}from"./vendor-router-DDDcE-w_.js";import{u as B,V as T,t as C,W as p}from"./index-DztznN9U.js";import{g as H,R as L}from"./vendor-icons-BishvROv.js";import"./vendor-query-C2JOA1b6.js";import"./vendor-supabase-Bn8gZks7.js";import"./vendor-radix-C6yXmdLL.js";const m="/articles/pfas-remediation",R=t=>{const[a,n]=t.split("-").map(Number);return new Date(Date.UTC(a,n-1,1)).toLocaleDateString("en-US",{month:"long",year:"numeric",timeZone:"UTC"})},A=t=>{const[a,n]=t.split("-").map(Number);return new Date(Date.UTC(a,n-1,1)).toLocaleDateString("en-US",{month:"short",year:"2-digit",timeZone:"UTC"})},o=t=>t.toLocaleString("en-US"),P=t=>t===null?"n/a":`${(t*100).toFixed(0)}%`,g=t=>t===null?"n/a":t.toFixed(1);function l({value:t,higherIsBetter:a,suffix:n="",decimals:i=0}){if(t==null||Number.isNaN(t))return null;if(Math.abs(t)<(i>0?.05:.5))return e.jsx("span",{className:"text-xs font-semibold text-muted-foreground",children:"no change"});const c=a?t>0:t<0;return e.jsxs("span",{className:`text-xs font-semibold ${c?"text-primary":"text-destructive"}`,children:[t>0?"+":"",t.toFixed(i),n," vs prior month"]})}function d({label:t,value:a,delta:n,note:i}){return e.jsxs("div",{className:"rounded-md border border-border bg-card p-4",children:[e.jsx("div",{className:"text-[10px] font-bold uppercase tracking-[0.12em] text-muted-foreground",children:t}),e.jsx("div",{className:"mt-2 font-heading text-2xl font-bold text-foreground",children:a}),n?e.jsx("div",{className:"mt-1",children:n}):null,i?e.jsx("p",{className:"mt-2 text-xs leading-snug text-muted-foreground",children:i}):null]})}function x({headers:t,rows:a}){return a.length===0?e.jsx("p",{className:"py-6 text-sm text-muted-foreground",children:"No rows for this month."}):e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{children:e.jsx("tr",{className:"border-b border-border",children:t.map(n=>e.jsx("th",{className:"py-2 pr-4 text-left text-[10px] font-bold uppercase tracking-[0.12em] text-muted-foreground",children:n},n))})}),e.jsx("tbody",{children:a.map((n,i)=>e.jsx("tr",{className:"border-b border-border/50",children:n.map((c,h)=>e.jsx("td",{className:"py-2 pr-4 align-top text-foreground",children:c},h))},i))})]})})}function Z(){var j,N,w,y,v,S,k;B({title:"PFAS cluster tracking",description:"Internal",noIndex:!0});const[t,a]=u.useState([]),[n,i]=u.useState(!0),[c,h]=u.useState(!1),b=async()=>{i(!0);const{data:s,error:_}=await C.from("pfas_cluster_snapshots").select("*").order("month_key",{ascending:!1}).limit(24);_&&p({title:"Could not load snapshots",description:_.message}),a(s??[]),i(!1)};u.useEffect(()=>{b()},[]);const I=async()=>{h(!0);const{error:s}=await C.functions.invoke("pfas-cluster-snapshot",{body:{}});if(h(!1),s){p({title:"Rebuild failed",description:s.message});return}p({title:"Snapshot rebuilt",description:"Search Console data pulled for the month that just closed. No email sent."}),b()},r=t[0],f=u.useMemo(()=>[...t].reverse(),[t]);return e.jsxs("main",{className:"mx-auto max-w-6xl px-6 py-10",children:[e.jsxs("div",{className:"mb-8 flex flex-wrap items-center justify-between gap-4",children:[e.jsxs("div",{children:[e.jsxs(F,{to:"/admin/seo-tracking",className:"inline-flex items-center gap-2 text-sm text-muted-foreground hover:text-foreground",children:[e.jsx(H,{className:"h-4 w-4"})," SEO tracking"]}),e.jsx("h1",{className:"mt-2 font-heading text-3xl font-bold text-foreground",children:"PFAS cluster consolidation"}),e.jsx("p",{className:"mt-1 max-w-2xl text-sm text-muted-foreground",children:"Monthly Search Console readout for the PFAS hub, its four supporting pages and the two deferring pages. The test each cycle is whether impressions and best rankings are moving onto the hub."})]}),e.jsxs(T,{variant:"outline",onClick:I,disabled:c,children:[e.jsx(L,{className:`mr-2 h-4 w-4 ${c?"animate-spin":""}`}),"Rebuild snapshot"]})]}),n?e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading."}):null,!n&&!r?e.jsx("div",{className:"rounded-md border border-border bg-card p-6",children:e.jsx("p",{className:"text-sm text-foreground",children:"No snapshots yet. Click Rebuild snapshot to pull the month that just closed. After that it runs automatically on the first of each month."})}):null,r?e.jsxs(e.Fragment,{children:[e.jsxs("p",{className:"mb-3 text-xs uppercase tracking-[0.12em] text-muted-foreground",children:[R(r.month_key)," (",r.period_start," to ",r.period_end,")"]}),e.jsxs("section",{className:"grid gap-3 sm:grid-cols-2 lg:grid-cols-4",children:[e.jsx(d,{label:"Hub share of cluster impressions",value:P(r.hub_impression_share),delta:e.jsx(l,{value:typeof((j=r.deltas)==null?void 0:j.hubShare)=="number"?r.deltas.hubShare*100:null,higherIsBetter:!0,suffix:" pts",decimals:1}
1),note:"Rising means search is settling on the hub rather than spreading across the cluster."}),e.jsx(d,{label:"Hub average position",value:g(r.hub_position),delta:e.jsx(l,{value:(N=r.deltas)==null?void 0:N.hubPosition,higherIsBetter:!1,decimals:1}),note:"Lower is better. This is the ranking the consolidation is meant to lift."}),e.jsx(d,{label:"Contested queries won by hub",value:`${r.hub_won_queries} of ${r.shared_queries}`,delta:e.jsx(l,{value:(w=r.deltas)==null?void 0:w.hubWonQueries,higherIsBetter:!0}),note:"Queries where more than one PFAS page appears, and the hub ranks best."}),e.jsx(d,{label:"Still split across pages",value:o(r.split_queries),delta:e.jsx(l,{value:(y=r.deltas)==null?void 0:y.splitQueries,higherIsBetter:!1}),note:"Falling means the cannibalisation is clearing. These are the queries to watch."})]}),e.jsxs("section",{className:"mt-8",children:[e.jsx("h2",{className:"mb-3 font-heading text-lg font-bold text-foreground",children:"Cluster totals"}),e.jsxs("div",{className:"grid gap-3 sm:grid-cols-3",children:[e.jsx(d,{label:"Cluster impressions",value:o(r.cluster_impressions),delta:e.jsx(l,{value:(v=r.deltas)==null?void 0:v.clusterImpressions,higherIsBetter:!0})}),e.jsx(d,{label:"Cluster clicks",value:o(r.cluster_clicks),delta:e.jsx(l,{value:(S=r.deltas)==null?void 0:S.clusterClicks,higherIsBetter:!0})}),e.jsx(d,{label:"Hub impressions",value:o(r.hub_impressions),delta:e.jsx(l,{value:(k=r.deltas)==null?void 0:k.hubImpressions,higherIsBetter:!0})})]})]}),e.jsxs("section",{className:"mt-8",children:[e.jsx("h2",{className:"mb-3 font-heading text-lg font-bold text-foreground",children:"Page by page"}),e.jsx(x,{headers:["Page","Role","Impressions","Clicks","Position","Queries"],rows:(r.pages??[]).map(s=>[e.jsxs("span",{className:s.path===m?"font-semibold":"",children:[s.label,e.jsx("span",{className:"block text-xs text-muted-foreground",children:s.path})]}),s.role,o(s.impressions),o(s.clicks),g(s.position),o(s.queries)])})]}),e.jsxs("section",{className:"mt-8",children:[e.jsx("h2",{className:"mb-1 font-heading text-lg font-bold text-foreground",children:"Queries still surfacing more than one PFAS page"}),e.jsx("p",{className:"mb-3 text-xs text-muted-foreground",children:"These are the ones consolidation has not resolved. Where the winner is not the hub, the supporting page is outranking it for intent the hub is meant to own."}),e.jsx(x,{headers:["Query","Impressions","Pages","Best page","Best pos","Hub pos"],rows:(r.queries??[]).filter(s=>s.pages>1).slice(0,40).map(s=>[s.query,o(s.impressions),s.pages,e.jsx("span",{className:s.winner===m?"font-semibold text-primary":"",children:s.winner===m?"hub":s.winner}),s.winnerPosition.toFixed(1),s.hubPosition===null?"absent":s.hubPosition.toFixed(1)])})]}),e.jsxs("section",{className:"mt-8",children:[e.jsx("h2",{className:"mb-3 font-heading text-lg font-bold text-foreground",children:"Top cluster queries"}),e.jsx(x,{headers:["Query","Impressions","Clicks","Best page","Hub pos"],rows:(r.queries??[]).slice(0,25).map(s=>[s.query,o(s.impressions),o(s.clicks),s.winner===m?"hub":s.winner,s.hubPosition===null?"absent":s.hubPosition.toFixed(1)])})]}),f.length>1?e.jsxs("section",{className:"mt-8",children:[e.jsx("h2",{className:"mb-3 font-heading text-lg font-bold text-foreground",children:"Cycle over cycle"}),e.jsx(x,{headers:["Month","Hub share","Hub pos","Hub impressions","Cluster impressions","Split queries"],rows:f.map(s=>[A(s.month_key),P(s.hub_impression_share),g(s.hub_position),o(s.hub_impressions),o(s.cluster_impressions),o(s.split_queries)])})]}):null,e.jsx("p",{className:"mt-10 border-t border-border pt-4 text-xs leading-relaxed text-muted-foreground",children:"Read the share and the split count as the signal, not the raw totals. Search Console reports the page it showed for a query, so a query counts as split only when Google actually surfaced two cluster pages in the same month. Nothing on this page is emailed to anyone."})]}):null]})}export{Z as default};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.