PageSourceSearch

https://dashboard.morvo.co.uk/assets/AdminDashboard-kRWbZ5HC.js

js morvo.co.uk collected 2026-09-24 09:53:15 UTC 2,797 bytes, 1 lines download raw bytes

1import{r as g,ae as v,e as D,aA as R,j as s,U as a}from"./index-CRQcHE7J.js";import{C as N,a as w,b as $,c as U}from"./card-DWLMxT6t.js";import{b as x,c as q}from"./billingRail-3eeNa8sg.js";import{B}from"./banknote-BAIT-iS_.js";const r=()=>({GBP:0,USD:0}),l=e=>["GBP","USD"].filter(n=>e[n]>0).map(n=>`${q(n)}${e[n].toLocaleString("en-GB",{maximumFractionDigits:0})}`).join(" + ")||"$0",c=e=>Number(e.custom_price_override??e.monthly_price)||0,T=(e,n)=>e.subscription_status==="trial"||!!e.trial_end_date&&new Date(e.trial_end_date).getTime()>n;function A(){const[e,n]=g.useState({totalClients:0,openSupport:0,recurring:r(),paying:0,trialRecurring:r(),trials:0,collected:r()});g.useEffect(()=>{(async()=>{const i=new Date;i.setDate(1),i.setHours(0,0,0,0);const[y,_,b,S]=await Promise.all([a.from("clients").select("*",{count:"exact",head:!0}),a.from("clients").select("billing_source, shopify_domain, billing_currency, monthly_price, custom_price_override, subscription_status, trial_end_date, is_demo, is_lifetime").eq("active",!0),a.from("billing_payments").select("amount, currency").eq("status","confirmed").gte("created_at",i.toISOString()),a.from("support_requests").select("*",{count:"exact",head:!0}).eq("status","open")]),j=Date.now(),C=(_.data??[]).filter(t=>!t.is_demo&&!t.is_lifetime&&c(t)>0&&t.subscription_status!=="pending"&&t.subscription_status!=="cancelled"),u=r(),p=r();let m=0,d=0;for(const t of C)T(t,j)?(p[x(t)]+=c(t),d++):(u[x(t)]+=c(t),m++);const f=r();for(const t of b.data??[])f[t.currency==="USD"?"USD":"GBP"]+=Number(t.amount)||0;n({totalClients:y.count||0,openSupport:S.count||0,recurring:u,paying:m,trialRecurring:p,trials:d,collected:f})})()},[]);const h=[{title:"Total Clients",value:e.totalClients,icon:v,color:"text-blue-600"},{title:"Monthly Recurring Revenue",value:l(e.recurring),note:`${e.paying} paying${e.trials?`, ${e.trials} on free trial worth ${l(e.trialRecurring)}`:""}`,icon:D,color:"text-green-600"},{title:"Collected This Month",value:l(e.collected),note:"Card payments. Shopify pays out separately.",icon:B,color:"text-purple-600"},{title:"Open Support Requests",value:e.openSupport,icon:R,color:"text-orange-600"}];return s.jsxs("div",{className:"space-y-6",children:[s.jsx("h1",{className:"text-3xl font-bold",children:"Admin Dashboard"}),s.jsx("div",{className:"grid gap-4 md:grid-cols-2 lg:grid-cols-4",children:h.map(o=>s.jsxs(N,{children:[s.jsxs(w,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[s.jsx($,{className:"text-sm font-medium",children:o.title}),s.jsx(o.icon,{className:`h-4 w-4 ${o.color}`})]}),s.jsxs(U,{children:[s.jsx("div",{className:"text-2xl font-bold",children:o.value}),o.note&&s.jsx("p",{className:"text-xs text-muted-foreground",children:o.note})]})]},o.title))})]})}export{A 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.