1import{r as l,j as e,L as u}from"./react-vendor-CAvUCgBg.js";import{A as x}from"./AdminLayout-DWLBa2X7.js";import{B as h,C as c,b as g,s as f}from"./index-BD5OT4An.js";import{a4 as p,ab as b,ag as k}from"./icons-B1xxNXCI.js";import"./query-C7ekqVw8.js";import"./class-utils-B2rm_Apj.js";import"./supabase-L6Z3U_Fd.js";import"./radix-5feLYWdW.js";const a=t=>t==null?"â":t.toLocaleString(),m=t=>t==null?"â":`${t}%`,y=t=>{if(t==null)return"â";if(t<60)return`${Math.round(t)}s`;const n=Math.floor(t/60),r=Math.round(t%60);return`${n}m ${r}s`},j=t=>t==null?"â":`$${t.toLocaleString()}`,N=[{key:"dau",label:"Real (human) DAU",measure:"live_user_pings minus bot UA",target:"10K",format:a,wired:!0},{key:"mau",label:"MAU",measure:"distinct session in 30d",target:"150K",format:a,wired:!0},{key:"d7_retention_pct",label:"D7 retention (signups)",measure:"% of week-1 cohort active in week 2",target:"30%",format:m,wired:!0},{key:"d30_retention_pct",label:"D30 retention",measure:"same, week 5",target:"20%",format:m,wired:!0},{key:"ads_per_day",label:"Ads posted / day",measure:"ads INSERT/day",target:"2K",format:a,wired:!0},{key:"msgs_per_day",label:"Chat msgs / day",measure:"messages INSERT/day",target:"20K",format:a,wired:!0},{key:"median_session_seconds",label:"Median session length",measure:"live_user_pings (last - first seen)",target:"3 min",format:y,wired:!0},{key:"gsc_clicks_per_day",label:"Organic search traffic",measure:"GSC clicks/day",target:"5K/day",format:a,wired:!1,todo:{text:"Wire GSC API ingest",href:"/admin/gsc-submissions"}},{key:"indexed_pages",label:"Indexed pages (submitted)",measure:"distinct URLs submitted to GSC",target:"50K",format:a,wired:!0},{key:"backlinks_new_per_week",label:"Backlinks (new/week)",measure:"Semrush backlink_analysis",target:"+50/week",format:a,wired:!1,todo:{text:"Run Semrush from /admin/backlinks",href:"/admin/backlinks"}},{key:"mrr_usd",label:"MRR",measure:"Stripe",target:"$25K",format:j,wired:!1,todo:{text:"Charging is OFF â enable in Monetization",href:"/admin/monetization"}},{key:"nps",label:"NPS / referral rate",measure:"in-product survey",target:"30+",format:t=>t==null?"â":String(t),wired:!1,todo:{text:"Ship in-product NPS survey (not built)"}}],L=()=>{const[t,n]=l.useState(null),[r,d]=l.useState(!0),o=async()=>{d(!0);const{data:s,error:i}=await f.rpc("get_kpi_dashboard");!i&&s&&n(s),d(!1)};return l.useEffect(()=>{o()},[]),e.jsx(x,{children:e.jsxs("div",{className:"max-w-5xl mx-auto p-4 md:p-8 space-y-6",children:[e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsxs("div",{children:[e.jsxs("h1",{className:"text-2xl font-bold text-foreground flex items-center gap-2",children:[e.jsx(p,{className:"w-6 h-6 text-[hsl(var(--brand-yellow))]"})," KPI Dashboard"]}),e.jsxs("p",{className:"text-sm text-muted-foreground mt-1",children:["The 12 numbers. Refresh daily. ",e.jsx("em",{children:`"We don't measure that" is the wrong answer.`})]})]}),e.jsxs(h,{variant:"outline",size:"sm",onClick:o,className:"gap-1",children:[e.jsx(b,{className:`w-3 h-3 ${r?"animate-spin":""}`})," Refresh"]})]}),e.jsxs(c,{className:"overflow-hidden",children:[e.jsxs("div",{className:"grid grid-cols-12 gap-2 px-4 py-2 bg-[hsl(var(--brand-red))] text-white text-xs font-bold uppercase tracking-wide",children:[e.jsx("div",{className:"col-span-4",children:"KPI"}),e.jsx("div",{className:"col-span-4",children:"How to measure"}),e.jsx("div",{className:"col-span-2 text-right",children:"Today"}),e.jsx("div",{className:"col-span-2 text-right",children:"Q1 target"})]}),N.map(s=>{const i=t?t[s.key]:null;return e.jsxs("div",{className:"grid grid-cols-12 gap-2 px-4 py-3 text-sm border-b border-border last:border-b-0 items-center hover:bg-muted/30",children:[e.jsxs("div",{className:"col-span-4",children:[e.jsx("div",{className:"font-semibold text-foreground",children:s.label}),!s.wired&&s.todo&&e.jsxs("div",{className:"mt-1 flex items-start gap-1 text-[11px] text-amber-700 dark:text-amber-400",children:[e.jsx(k,{className:"w-3 h-3 mt-0.5 shrink-0"}),s.todo.href?e.jsx(u,{to:s.todo.href,className:"underline hover:no-underline",children:s.todo.text}):e.jsx("span",{children:s.todo.text})]})]}),e.jsx("div",{className:"col-span-4 text-xs text-muted-foreground",children:s.measure}),e.jsx("div",{className:"col-span-2 text-right",children:e.jsx("span",{className:`font-black tabular-nums ${s.wired?"text-foreground":"text-muted-foreground"} text-lg`,children:r?"â¦":s.format(i)})}),e.jsx("div",{className:"col-span-2 text-right",children:e.jsx(g,{variant:"outline",className:"font-mono text-xs",children:s.target})})]},s.key)})]}),e.jsx(c,{className:"p-4 bg-muted/40",children:e.jsxs("p",{className:"text-xs text-muted-foreground leading-relaxed",children:[e.jsx("strong",{children:"Computed live from the database."})," Bot pings excluded from DAU/MAU/session-length. Retention cohorts use ",e.jsx("code",{children:"profiles.created_at"})," + ",e.jsx("code",{children:"last_active_at"})," (heartbeat must be active). Greyed rows need an external integration before they show real numbers â
1click the action under each one.",(t==null?void 0:t.computed_at)&&e.jsxs(e.Fragment,{children:[" Last refresh: ",new Date(t.computed_at).toLocaleString(),"."]})]})})]})})};export{L 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.