PageSourceSearch

https://nookly.com/assets/CostTracker-DrjfXi8s.js

js nookly.com collected 2026-09-24 13:28:08 UTC 15,798 bytes, 2 lines download raw bytes

1import{r as i,j as e}from"./vendor-framer-RW7l0Jrm.js";import{c as ae,W as we,g as Ce,Y as T,z as Y,D as G,E as w,av as J,a6 as u,a7 as g,a8 as p,U as be,a9 as y,af as Se,F as ke,bd as D,a0 as C,a1 as I,s as b}from"./index-DK-SlJ-2.js";import{T as Te,a as De,b as K,c as x,d as Ae,e as m}from"./table-5JdZCNZw.js";import{S as Q}from"./switch-D0P0o8Ho.js";import{u as Me}from"./useAdminAuth-B6gYQFR0.js";import{R as A}from"./refresh-cw-u3YMsbBk.js";import{D as Fe}from"./download-B9V2Kw45.js";import{T as Z}from"./trending-up-Dhuh-9So.js";import{s as M}from"./subDays-B3wmoNhL.js";import{C as ee}from"./circle-check-big-BwLdoCOu.js";import{S as Re}from"./send-0qPnYxV4.js";import{C as Ee}from"./circle-x-Bv9lKzLf.js";import{f as j,s as se}from"./format-DlXK3-RM.js";const te=ae("Bell",[["path",{d:"M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9",key:"1qo2s2"}],["path",{d:"M10.3 21a1.94 1.94 0 0 0 3.4 0",key:"qgo35s"}]]);const Le=ae("Settings",[["path",{d:"M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z",key:"1qme2f"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]]),Ge=()=>{Me();const{toast:_}=we(),[F,$]=i.useState(!0),[S,le]=i.useState([]),[re,oe]=i.useState(null),[ne,ie]=i.useState(null),[ce,de]=i.useState(null),[H,he]=i.useState([]),[P,xe]=i.useState("7d"),[me,je]=i.useState("overview"),[a,v]=i.useState(null),[O,ue]=i.useState([]),[U,B]=i.useState(!1),[V,q]=i.useState(!1),R=async()=>{$(!0);try{const{data:s,error:l}=await b.from("story_cost_summary").select("*").order("story_created_at",{ascending:!1}).limit(100);if(l)throw l;le(s||[]);const n=new Date,o=se(M(n,7)),f=se(M(n,30)),r=s||[],t=r.filter(d=>new Date(d.story_created_at)>=o);oe(E(t));const z=r.filter(d=>new Date(d.story_created_at)>=f);ie(E(z)),de(E(r));const L=new Map;z.forEach(d=>{const N=j(new Date(d.story_created_at),"yyyy-MM-dd"),h=L.get(N)||{cost:0,count:0};L.set(N,{cost:h.cost+d.total_cost_dollars,count:h.count+1})});const W=[];for(let d=29;d>=0;d--){const N=j(M(n,d),"yyyy-MM-dd"),h=L.get(N);W.push({date:N,cost_dollars:(h==null?void 0:h.cost)||0,story_count:(h==null?void 0:h.count)||0})}he(W);const{data:X,error:_e}=await b.from("cost_alert_settings").select("*").eq("id","00000000-0000-0000-0000-000000000001").single();!_e&&X&&v(X);const{data:ve,error:Ne}=await b.from("cost_alert_log").select("*").order("created_at",{ascending:!1}).limit(20);Ne||ue(ve||[])}catch(s){console.error("Error fetching cost data:",s),_({title:"Error",description:"Failed to load cost data. Make sure you have admin access.",variant:"destructive"})}finally{$(!1)}};i.useEffect(()=>{R()},[]);const E=s=>{if(s.length===0)return{totalStories:0,totalCostDollars:0,avgCostPerStory:0,avgCostPerImage:0,totalOutlineCost:0,totalCharacterCost:0,totalPageCost:0,retryRate:0};const l=s.reduce((r,t)=>r+t.total_cost_dollars,0),n=s.reduce((r,t)=>r+t.page_calls+t.character_calls,0),o=s.reduce((r,t)=>r+t.retry_count,0),f=s.reduce((r,t)=>r+t.outline_calls+t.revision_calls+t.character_calls+t.page_calls,0);return{totalStories:s.length,totalCostDollars:l,avgCostPerStory:l/s.length,avgCostPerImage:n>0?l/n:0,totalOutlineCost:0,totalCharacterCost:0,totalPageCost:0,retryRate:f>0?o/f*100:0}},ge=()=>{const s=["Story ID","Child Name","Age","Theme","Created","Status","Outline Calls","Revisions","Character Calls","Page Calls","Retries","Prompt Tokens","Completion Tokens","Total Cost ($)"],l=S.map(t=>[t.story_draft_id,t.child_name,t.child_age||"",t.story_theme||"",j(new Date(t.story_created_at),"yyyy-MM-dd HH:mm"),t.status,t.outline_calls,t.revision_calls,t.character_calls,t.page_calls,t.retry_count,t.total_prompt_tokens,t.total_completion_tokens,t.total_cost_dollars.toFixed(6)]),n=[s.join(","),...l.map(t=>t.join(","))].join(`
2`),o=new Blob([n],{type:"text/csv"}
2),f=URL.createObjectURL(o),r=document.createElement("a");r.href=f,r.download=`nookly-costs-${j(new Date,"yyyy-MM-dd")}.csv`,r.click(),URL.revokeObjectURL(f)},pe=()=>{switch(P){case"7d":return re;case"30d":return ne;case"all":return ce}},k=s=>s<.01?`$${s.toFixed(6)}`:`$${s.toFixed(4)}`,ye=async()=>{if(a){B(!0);try{const{error:s}=await b.from("cost_alert_settings").update({daily_threshold_dollars:a.daily_threshold_dollars,weekly_threshold_dollars:a.weekly_threshold_dollars,alert_emails:a.alert_emails,daily_alerts_enabled:a.daily_alerts_enabled,weekly_alerts_enabled:a.weekly_alerts_enabled}).eq("id","00000000-0000-0000-0000-000000000001");if(s)throw s;_({title:"Settings saved",description:"Alert settings have been updated."})}catch(s){console.error("Error saving settings:",s),_({title:"Error",description:"Failed to save settings.",variant:"destructive"})}finally{B(!1)}}},fe=async s=>{var l,n;q(!0);try{const o=await b.functions.invoke("check-cost-alerts",{body:{test:!0,alertType:s}});if(o.error)throw o.error;(l=o.data)!=null&&l.emailSent?_({title:"Test alert sent",description:`A test ${s} alert was sent to the configured recipients.`}):_({title:"Alert not sent",description:((n=o.data)==null?void 0:n.error)||"Check that recipients are configured.",variant:"destructive"}),R()}catch(o){console.error("Error sending test alert:",o),_({title:"Error",description:"Failed to send test alert.",variant:"destructive"})}finally{q(!1)}},c=pe();return e.jsxs(e.Fragment,{children:[e.jsx(Ce,{title:"Cost Tracker | Nookly Admin",description:"Admin dashboard page.",noIndex:!0}),e.jsx("div",{className:"min-h-screen bg-background",children:e.jsxs("div",{className:"container mx-auto px-4 py-8",children:[e.jsxs("div",{className:"flex items-center justify-between mb-8",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-3xl font-bold",children:"Cost Tracker"}),e.jsx("p",{className:"text-muted-foreground",children:"AI generation costs & unit economics"})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs(T,{variant:"outline",onClick:R,disabled:F,children:[e.jsx(A,{className:`h-4 w-4 mr-2 ${F?"animate-spin":""}`}),"Refresh"]}),e.jsxs(T,{variant:"outline",onClick:ge,disabled:S.length===0,children:[e.jsx(Fe,{className:"h-4 w-4 mr-2"}),"Export CSV"]})]})]}),e.jsxs(Y,{value:me,onValueChange:s=>je(s),className:"mb-6",children:[e.jsxs(G,{children:[e.jsxs(w,{value:"overview",className:"flex items-center gap-2",children:[e.jsx(Z,{className:"h-4 w-4"}),"Overview"]}),e.jsxs(w,{value:"settings",className:"flex items-center gap-2",children:[e.jsx(te,{className:"h-4 w-4"}),"Alert Settings"]})]}),e.jsxs(J,{value:"overview",className:"mt-6",children:[e.jsx(Y,{value:P,onValueChange:s=>xe(s),className:"mb-6",children:e.jsxs(G,{children:[e.jsx(w,{value:"7d",children:"Last 7 Days"}),e.jsx(w,{value:"30d",children:"Last 30 Days"}),e.jsx(w,{value:"all",children:"All Time"})]})}),e.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-8",children:[e.jsxs(u,{children:[e.jsxs(g,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(p,{className:"text-sm font-medium",children:"Total Stories"}),e.jsx(be,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(y,{children:[e.jsx("div",{className:"text-2xl font-bold",children:(c==null?void 0:c.totalStories)||0}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"stories generated"})]})]}),e.jsxs(u,{children:[e.jsxs(g,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(p,{className:"text-sm font-medium",children:"Total Cost"}),e.jsx(Se,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(y,{children:[e.jsx("div",{className:"text-2xl font-bold",children:k((c==null?void 0:c.totalCostDollars)||0)}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"AI generation costs"})]})]}),e.jsxs(u,{children:[e.jsxs(g,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(p,{className:"text-sm font-medium",children:"Avg Cost/Story"}),e.jsx(ke,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(y,{children:[e.jsx("div",{className:"text-2xl font-bold",children:k((c==null?void 0:c.avgCostPerStory)||0)}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"per complete story"})]})]}),e.jsxs(u,{children:[e.jsxs(g,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(p,{className:"text-sm font-medium",children:"Retry Rate"}),e.jsx(Z,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsxs(y,{children:[e.jsxs("div",{className:"text-2xl font-bold",children:[((c==null?void 0:c.retryRate)||0).toFixed(1),"%"]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"of calls are retries"})]})]})]}),e.jsxs(u,{className:"mb-8",children:[e.jsxs(g,{children:[e.jsx(p,{children:"Daily Cost Trend (Last 30 Days)"}),e.jsx(D,{children:"Cost per day with story count"})]}),e.jsxs(y,{children:[e.jsx("div",{className:"h-[200px] flex items-end gap-1",children:H.map(s=>{const l=Math.max(...H.map(o=>o.cost_dollars),.001),n=s.cost_dollars/l*100;return e.jsx("div",{className:"flex-1 bg-primary/20 hover:bg-primary/40 transition-colors rounded-t relative group",style:{height:`${Math.max(n,2)}%`},children:e.jsxs("div",{className:"absolute bottom-full mb-2 left-1/2 -translate-x-1/2 bg-popover text-popover-foreground px-2 py-1 rounded text-xs whitespace-nowrap opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none z-10 shadow-lg",children:[e.jsx("div",{className:"font-medium",children:j(new Date(s.date),"MMM d")}),e.jsx("div",{children:k(s.cost_dollars)}),e.jsxs("div",{children:[s.story_count," stories"]})]})},s.date)})}),e.jsxs("div",{className:"flex justify-between mt-2 text-xs text-muted-foreground",children:[e.jsx("span",{children:j(M(new Date,29),"MMM d")}),e.jsx("span",{children:j(new Date,"MMM d")})]})]})]}),e.jsxs(u,{children:[e.jsxs(g,{children:[e.jsx(p,{children:"Story Cost Details"}),e.jsx(D,{children:"Individual story generation costs (most recent 100)"})]}),e.jsx(y,{children:F?e.jsx("div",{className:"flex items-center justify-center py-8",children:e.jsx(A,{className:"h-6 w-6 animate-spin text-muted-foreground"})}):S.length===0?e.jsx("div",{className:"text-center py-8 text-muted-foreground",children:"No cost data yet. Costs will appear here as stories are generated."}):e.jsx("div",{className:"overflow-x-auto",children:e.jsxs(Te,{children:[e.jsx(De,{children:e.jsxs(K,{children:[e.jsx(x,{children:"Child"}),e.jsx(x,{children:"Theme"}),e.jsx(x,{children:"Age"}),e.jsx(x,{className:"text-center",children:"Outline"}),e.jsx(x,{className:"text-center",children:"Character"}),e.jsx(x,{className:"text-center",children:"Pages"}),e.jsx(x,{className:"text-center",children:"Retries"}),e.jsx(x,{className:"text-right",children:"Total Cost"}),e.jsx(x,{children:"Created"})]})}),e.jsx(Ae,{children:S.map(s=>e.jsxs(K,{children:[e.jsx(m,{className:"font-medium",children:s.child_
2name}),e.jsx(m,{children:s.story_theme||"-"}),e.jsx(m,{children:s.child_age||"-"}),e.jsx(m,{className:"text-center",children:s.outline_calls+s.revision_calls}),e.jsx(m,{className:"text-center",children:s.character_calls}),e.jsx(m,{className:"text-center",children:s.page_calls}),e.jsxs(m,{className:"text-center",children:[s.retry_count>0&&e.jsx("span",{className:"text-orange-500",children:s.retry_count}),s.retry_count===0&&"-"]}),e.jsx(m,{className:"text-right font-mono",children:k(s.total_cost_dollars)}),e.jsx(m,{className:"text-muted-foreground",children:j(new Date(s.story_created_at),"MMM d, HH:mm")})]},s.story_draft_id))})]})})})]})]}),e.jsx(J,{value:"settings",className:"mt-6",children:e.jsxs("div",{className:"grid gap-6 md:grid-cols-2",children:[e.jsxs(u,{children:[e.jsxs(g,{children:[e.jsxs(p,{className:"flex items-center gap-2",children:[e.jsx(Le,{className:"h-5 w-5"}),"Alert Configuration"]}),e.jsx(D,{children:"Configure cost thresholds and notification settings"})]}),e.jsx(y,{className:"space-y-6",children:a&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(C,{htmlFor:"daily-alerts",className:"font-medium",children:"Daily Alerts"}),e.jsx(Q,{id:"daily-alerts",checked:a.daily_alerts_enabled,onCheckedChange:s=>v({...a,daily_alerts_enabled:s})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"daily-threshold",children:"Daily Threshold ($)"}),e.jsx(I,{id:"daily-threshold",type:"number",step:"0.01",min:"0",value:a.daily_threshold_dollars,onChange:s=>v({...a,daily_threshold_dollars:parseFloat(s.target.value)||0}),disabled:!a.daily_alerts_enabled})]})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(C,{htmlFor:"weekly-alerts",className:"font-medium",children:"Weekly Alerts"}),e.jsx(Q,{id:"weekly-alerts",checked:a.weekly_alerts_enabled,onCheckedChange:s=>v({...a,weekly_alerts_enabled:s})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"weekly-threshold",children:"Weekly Threshold ($)"}),e.jsx(I,{id:"weekly-threshold",type:"number",step:"0.01",min:"0",value:a.weekly_threshold_dollars,onChange:s=>v({...a,weekly_threshold_dollars:parseFloat(s.target.value)||0}),disabled:!a.weekly_alerts_enabled})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(C,{htmlFor:"alert-emails",children:"Alert Recipients"}),e.jsx(I,{id:"alert-emails",type:"text",placeholder:"[email protected], [email protected]",value:a.alert_emails,onChange:s=>v({...a,alert_emails:s.target.value})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Comma-separated list of email addresses"})]}),e.jsxs("div",{className:"flex gap-2 pt-4",children:[e.jsxs(T,{onClick:ye,disabled:U,children:[U?e.jsx(A,{className:"h-4 w-4 mr-2 animate-spin"}):e.jsx(ee,{className:"h-4 w-4 mr-2"}),"Save Settings"]}),e.jsxs(T,{variant:"outline",onClick:()=>fe("daily"),disabled:V||!a.alert_emails,children:[V?e.jsx(A,{className:"h-4 w-4 mr-2 animate-spin"}):e.jsx(Re,{className:"h-4 w-4 mr-2"}),"Send Test Alert"]})]})]})})]}),e.jsxs(u,{children:[e.jsxs(g,{children:[e.jsxs(p,{className:"flex items-center gap-2",children:[e.jsx(te,{className:"h-5 w-5"}),"Alert History"]}),e.jsx(D,{children:"Recent cost alerts sent to admins"})]}),e.jsx(y,{children:O.length===0?e.jsx("div",{className:"text-center py-8 text-muted-foreground",children:"No alerts sent yet. Alerts will appear here when thresholds are exceeded."}):e.jsx("div",{className:"space-y-3",children:O.map(s=>{var l;return e.jsxs("div",{className:"flex items-start gap-3 p-3 rounded-lg border bg-card",children:[s.email_sent?e.jsx(ee,{className:"h-5 w-5 text-green-500 mt-0.5 shrink-0"}):e.jsx(Ee,{className:"h-5 w-5 text-red-500 mt-0.5 shrink-0"}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"font-medium capitalize",children:s.alert_type}),e.jsxs("span",{className:"text-xs bg-muted px-2 py-0.5 rounded",children:[(l=s.overage_percent)==null?void 0:l.toFixed(0),"% of threshold"]})]}),e.jsxs("div",{className:"text-sm text-muted-foreground",children:["$",s.actual_cost_dollars.toFixed(2)," / $",s.threshold_dollars.toFixed(2)," threshold"]}),e.jsx("div",{className:"text-xs text-muted-foreground mt-1",children:j(new Date(s.created_at),"MMM d, yyyy HH:mm")}
2),s.email_error&&e.jsxs("div",{className:"text-xs text-red-500 mt-1",children:["Error: ",s.email_error]})]})]},s.id)})})})]})]})})]})]})})]})};export{Ge 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.