1import{j as e}from"./vendor-radix-BnNg3BH5.js";import{d as ye,b as le,s as f,w as M,x as I,y as V,z as A,A as F,B as p,F as H,L as K,D as Q,e as W,f as Y,g as X,v as P,I as G,G as te,q as b,a as _e,h as ie,U as we,V as Ne,W as Z,Y as ee}from"./index-Epr9psQo.js";import{r as v}from"./vendor-react-67mgcWXU.js";import{C as U,a as Ce,b as ke,c as Se,d as O}from"./card-DpKBVi42.js";import{T as ue,a as me,b as J,c as L,d as he,e as E}from"./table-023rHGnC.js";import{C as xe}from"./chart-column-6WlVTHnt.js";import{C as Re}from"./calendar-Ce69BthR.js";import{D as pe}from"./download-CDzT20jl.js";import{U as De}from"./users-uAR6_Qvs.js";import{D as $e}from"./dollar-sign-CC-jyV1q.js";import{F as Te}from"./folder-kanban-C52eeuLF.js";import{C as ne}from"./clock-BYWbH6MV.js";import{T as Fe}from"./trending-up-CXZcoU_y.js";import{B as je}from"./badge-Cl7apleB.js";import{S as Pe}from"./switch-ZTMCvIb3.js";import{C as se}from"./calendar-clock-Dgofoxff.js";import{P as fe}from"./plus-DRTmwF2W.js";import{M as ze}from"./mail-BWzQtSAz.js";import{P as ve}from"./play-CCgxmdCK.js";import{P as Be}from"./pencil-PwBd4M7u.js";import{T as ge}from"./trash-2-EIFrPvgK.js";import{u as qe,a as Ue,c as re}from"./vendor-query-PMAhJHCS.js";import{C as Oe}from"./checkbox-CaPhqoy3.js";import{e as Le,a as Ee}from"./reportBlockExport-DWdWM02C.js";import{f as Me}from"./format-Bw8okCdv.js";import"./vendor-supabase-CTlrDMdV.js";import"./vendor-charts-Dck3qfzI.js";import"./vendor-motion-CSzk-Fqg.js";import"./jszip.min-C-g80qGt.js";import"./_commonjs-dynamic-modules-TDtrdbi3.js";import"./en-US-DJiZ5LCQ.js";/** 2 * @license lucide-react v0.462.0 - ISC 3 * 4 * This source code is licensed under the ISC license. 5 * See the LICENSE file in the root directory of this source tree. 6 */const ae=ye("Blocks",[["rect",{width:"7",height:"7",x:"14",y:"3",rx:"1",key:"6d4xhi"}],["path",{d:"M10 21V8a1 1 0 0 0-1-1H4a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-5a1 1 0 0 0-1-1H3",key:"1fpvtg"}]]);function q(d){return d>=1e3?`$${(d/1e3).toFixed(1)}K`:`$${d.toFixed(0)}`}function Ie(){const{currentTenant:d}=le(),[h,y]=v.useState("utilization"),[j,S]=v.useState("month"),[N,C]=v.useState([]),[_,$]=v.useState(!0),[o,w]=v.useState({total:0,avg:0,count:0});v.useEffect(()=>{d?.id&&z()},[d?.id,h,j]);const T=()=>{const i=new Date;return j==="week"?new Date(i.getTime()-7*24*60*60*1e3).toISOString().split("T")[0]:j==="month"?new Date(i.getFullYear(),i.getMonth(),1).toISOString().split("T")[0]:j==="quarter"?new Date(i.getFullYear(),Math.floor(i.getMonth()/3)*3,1).toISOString().split("T")[0]:new Date(i.getFullYear(),0,1).toISOString().split("T")[0]},z=async()=>{if(!d?.id)return;$(!0);const i=T();try{if(h==="utilization"){const{data:u,error:m}=await f.rpc("get_utilization_report",{p_tenant_id:d.id,p_start_date:i});let l;if(!m&&u&&u.length>0)l=u.map(a=>({label:a.full_name||"Unknown",value:Number(a.total_hours)>0?Number(a.billable_hours)/Number(a.total_hours)*100:0,secondary:`${Number(a.billable_hours).toFixed(1)}h billable / ${Number(a.total_hours).toFixed(1)}h total`})).sort((a,n)=>n.value-a.value);else{const{data:a}=await f.from("time_entries").select("user_id, hours, is_billable, profiles:user_id(full_name)").eq("tenant_id",d.id).gte("date",i).limit(1e4),n={};for(const t of a||[])n[t.user_id]||(n[t.user_id]={name:t.profiles?.full_name||"Unknown",billable:0,total:0}),n[t.user_id].total+=t.hours||0,t.is_billable&&(n[t.user_id].billable+=t.hours||0);l=Object.values(n).map(t=>({label:t.name,value:t.total>0?t.billable/t.total*100:0,secondary:`${t.billable.toFixed(1)}h billable / ${t.total.toFixed(1)}h total`})).sort((t,r)=>r.value-t.value)}C(l),w({total:l.reduce((a,n)=>a+n.value,0),avg:l.length>0?l.reduce((a,n)=>a+n.value,0)/l.length:0,count:l.length})}else if(h==="revenue"){const{data:u}=await f.from("invoices").select("client_id, total_amount, status, clients:client_id(name)").eq("tenant_id",d.id).gte("invoice_date",i).limit(5e3),m={};for(const a of u||[])m[a.client_id]||(m[a.client_id]={name:a.clients?.name||"Unknown",amount:0}),m[a.client_id].amount+=a.total_amount||0;const l=Object.values(m).map(a=>({label:a.name,value:a.amount,secondary:q(a.amount)})).sort((a,n)=>n.value-a.value);C(l),w({total:l.reduce((a,n)=>a+n.value,0),avg:l.length>0?l.reduce((a,n)=>a+n.value,0)/l.length:0,count:l.length})}else if(h==="project_health"){const{data:u}=await f.from("projects").select("id, name, health_score, status, budget_amount, budget_used").eq("tenant_id",d.id).eq("status","active").limit(100),m=(u||[]).map(l
6=>({label:l.name,value:l.health_score||50,secondary:l.budget_amount?`${q(l.budget_used||0)} / ${q(l.budget_amount)}`:"No budget"})).sort((l,a)=>l.value-a.value);C(m),w({total:m.length,avg:m.length>0?m.reduce((l,a)=>l+a.value,0)/m.length:0,count:m.length})}else if(h==="time_by_project"){const{data:u,error:m}=await f.rpc("get_time_by_project_report",{p_tenant_id:d.id,p_start_date:i});let l;if(!m&&u&&u.length>0)l=u.map(a=>({label:a.project_name||"Unknown",value:Number(a.total_hours),secondary:`${Number(a.billable_hours).toFixed(1)}h billable`})).sort((a,n)=>n.value-a.value);else{const{data:a}=await f.from("time_entries").select("project_id, hours, is_billable, projects:project_id(name)").eq("tenant_id",d.id).gte("date",i).limit(1e4),n={};for(const t of a||[])t.project_id&&(n[t.project_id]||(n[t.project_id]={name:t.projects?.name||"Unknown",hours:0,billable:0}),n[t.project_id].hours+=t.hours||0,t.is_billable&&(n[t.project_id].billable+=t.hours||0));l=Object.values(n).map(t=>({label:t.name,value:t.hours,secondary:`${t.billable.toFixed(1)}h billable`})).sort((t,r)=>r.value-t.value)}C(l),w({total:l.reduce((a,n)=>a+n.value,0),avg:0,count:l.length})}else if(h==="team_capacity"){const{data:u,error:m}=await f.rpc("get_team_capacity_report",{p_tenant_id:d.id,p_start_date:i});let l;const a=j==="week"?1:j==="month"?4:j==="quarter"?13:52;if(!m&&u&&u.length>0)l=u.map(n=>{const t=(Number(n.capacity_hours_per_week)||40)*a,r=Number(n.logged_hours);return{label:n.full_name||"Unknown",value:t>0?r/t*100:0,secondary:`${r.toFixed(0)}h / ${t}h capacity`}}).sort((n,t)=>t.value-n.value);else{const[{data:n},{data:t}]=await Promise.all([f.from("profiles").select("id, full_name, capacity_hours_per_week").eq("tenant_id",d.id).limit(200),f.from("time_entries").select("user_id, hours").eq("tenant_id",d.id).gte("date",T()).limit(1e4)]),r={};for(const g of t||[])r[g.user_id]=(r[g.user_id]||0)+(g.hours||0);l=(n||[]).map(g=>{const R=r[g.id]||0,s=(g.capacity_hours_per_week||40)*a;return{label:g.full_name||"Unknown",value:s>0?R/s*100:0,secondary:`${R.toFixed(0)}h / ${s}h capacity`}}).sort((g,R)=>R.value-g.value)}C(l),w({total:l.reduce((n,t)=>n+t.value,0),avg:l.length>0?l.reduce((n,t)=>n+t.value,0)/l.length:0,count:l.length})}}catch(u){console.error("Report load error:",u)}finally{$(!1)}},D=[{id:"utilization",label:"Utilization",icon:De,color:"text-info"},{id:"revenue",label:"Revenue by Client",icon:$e,color:"text-success"},{id:"project_health",label:"Project Health",icon:Te,color:"text-accent-purple"},{id:"time_by_project",label:"Time by Project",icon:ne,color:"text-warning"},{id:"team_capacity",label:"Team Capacity",icon:Fe,color:"text-accent-cyan"}];return e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsxs("h2",{className:"text-xl font-semibold flex items-center gap-2",children:[e.jsx(xe,{className:"h-5 w-5"}),"Reports"]}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Core business intelligence reports"})]}),e.jsxs(M,{value:j,onValueChange:S,children:[e.jsxs(I,{className:"w-36",children:[e.jsx(Re,{className:"h-3 w-3 mr-1"}),e.jsx(V,{})]}),e.jsxs(A,{children:[e.jsx(F,{value:"week",children:"This Week"}),e.jsx(F,{value:"month",children:"This Month"}),e.jsx(F,{value:"quarter",children:"This Quarter"}),e.jsx(F,{value:"year",children:"This Year"})]})]})]}),e.jsx("div",{className:"flex gap-2 flex-wrap",children:D.map(i=>e.jsxs(p,{variant:h===i.id?"default":"outline",size:"sm",onClick:()=>y(i.id),className:"text-xs",children:[e.jsx(i.icon,{className:`h-3 w-3 mr-1 ${h===i.id?"":i.color}`}),i.label]},i.id))}),e.jsxs(U,{children:[e.jsx(Ce,{children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx(ke,{className:"text-lg",children:D.find(i=>i.id===h)?.label}),e.jsxs(Se,{children:[o.count," items · ",h==="revenue"?q(o.total):`${o.avg.toFixed(1)}% avg`]})]}),N.length>0&&e.jsxs("div",{className:"flex gap-2",children:[e.jsxs(p,{variant:"outline",size:"sm",onClick:()=>{const i="Name,Value,Detail",u=N.map(t=>`"${t.label}",${t.value},"${t.secondary||""}"`).join(` 7`),m=`${i} 8${u}`,l=new Blob([m],{type:"text/csv"}),a=URL.createObjectURL(l),n=document.createElement("a");n.href=a,n.download=`${h}-${j}-${Date.now()}.csv`,n.click(),URL.revokeObjectURL(a)},children:[e.jsx(pe,{className:"h-3.5 w-3.5 mr-1"}),"CSV"]}),e.jsxs(p,{variant:"outline",size:"sm",onClick:()=>{const i=window.open("","_blank");if(!i)return;const u=D.find(l=>l.id===h)?.label||h,m=`<html><head><title>${u}</title> 9 <style>body{font-family:sans-serif;padding:24px}table{border-collapse:collapse;width:100%;font-size:12px}th,td{border:1px solid #ddd;padding:6px 8px;text-align:left}th{background:#f5f5f5;font-weight:600}tr:nth-child(even){background:#fafafa}h1{font-size:18px}</style> 10 </head><body><h1>${u}</h1><p style="color:#666;font-size:12px">${o.count} items • ${j}</p> 11 <table><thead><tr><th>
11Name</th><th>Value</th><th>Detail</th></tr></thead> 12 <tbody>${N.map(l=>`<tr><td>${l.label}</td><td>${h==="revenue"?q(l.value):l.value.toFixed(1)}</td><td>${l.secondary||""}</td></tr>`).join("")}</tbody></table> 13 <script>window.onload=function(){window.print()}<\/script></body></html>`;i.document.write(m),i.document.close()},children:[e.jsx(H,{className:"h-3.5 w-3.5 mr-1"}),"PDF"]})]})]})}),e.jsx(O,{children:_?e.jsx("div",{className:"py-8 text-center text-muted-foreground text-sm",children:"Loading report..."}):N.length===0?e.jsx("div",{className:"py-8 text-center text-muted-foreground text-sm",children:"No data for this period"}):e.jsxs(ue,{children:[e.jsx(me,{children:e.jsxs(J,{children:[e.jsx(L,{children:"Name"}),e.jsx(L,{className:"text-right",children:"Value"}),e.jsx(L,{children:"Detail"}),e.jsx(L,{className:"w-48",children:"Visual"})]})}),e.jsx(he,{children:N.slice(0,25).map((i,u)=>{const m=Math.max(...N.map(a=>a.value),1),l=i.value/m*100;return e.jsxs(J,{children:[e.jsx(E,{className:"font-medium",children:i.label}),e.jsx(E,{className:"text-right font-mono text-sm",children:h==="revenue"?q(i.value):h==="time_by_project"?`${i.value.toFixed(1)}h`:`${i.value.toFixed(1)}%`}),e.jsx(E,{className:"text-sm text-muted-foreground",children:i.secondary}),e.jsx(E,{children:e.jsx("div",{className:"w-full bg-muted rounded-full h-2",children:e.jsx("div",{className:"bg-primary rounded-full h-2 transition-all",style:{width:`${l}%`}})})})]},u)})})]})})]})]})}const oe=[{value:"utilization",label:"Utilization Report"},{value:"revenue",label:"Revenue by Client"},{value:"project_health",label:"Project Health Summary"},{value:"time_by_project",label:"Time by Project"},{value:"team_capacity",label:"Team Capacity"},{value:"budget_burndown",label:"Budget Burndown"},{value:"profitability",label:"Project Profitability"},{value:"ar_aging",label:"AR Aging Report"},{value:"executive_summary",label:"Executive Summary"}],ce=[{value:"daily",label:"Daily (9am)"},{value:"weekly",label:"Weekly (Monday)"},{value:"biweekly",label:"Bi-weekly"},{value:"monthly",label:"Monthly (1st)"},{value:"quarterly",label:"Quarterly"},{value:"end_of_month",label:"End of Month"}];function Ve(){const{currentTenant:d}=le(),[h,y]=v.useState([]),[j,S]=v.useState(!0),[N,C]=v.useState(!1),[_,$]=v.useState(null),[o,w]=v.useState({name:"",report_type:"",schedule:"",recipients:"",delivery_format:"inline"}),[T,z]=v.useState(null);v.useEffect(()=>{d?.id&&i()},[d?.id]);const D=async t=>{z(t);try{const{error:r}=await f.functions.invoke("execute-scheduled-reports",{body:{report_id:t}});r?b.error("Failed to run report: "+r.message):(b.success("Report executed successfully"),i())}catch{b.error("Failed to run report")}finally{z(null)}},i=async()=>{if(!d?.id)return;S(!0);const{data:t}=await f.from("scheduled_reports").select("*").eq("tenant_id",d.id).order("created_at",{ascending:!1}).limit(50);y(t||[]),S(!1)},u=async()=>{if(!d?.id||!o.name||!o.report_type||!o.schedule){b.error("Please fill in all required fields");return}const t=o.recipients.split(",").map(R=>R.trim()).filter(Boolean),r={tenant_id:d.id,name:o.name,report_type:o.report_type,schedule:o.schedule,recipients:t,is_active:!0,config:{delivery_format:o.delivery_format||"inline"}};let g;if(_?{error:g}=await f.from("scheduled_reports").update(r).eq("id",_):{error:g}=await f.from("scheduled_reports").insert(r),g){b.error("Failed to save: "+g.message);return}b.success(_?"Schedule updated":"Schedule created"),C(!1),i()},m=async(t,r)=>{const{error:g}=await f.from("scheduled_reports").update({is_active:r}).eq("id",t);if(g){b.error("Failed to update schedule: "+g.message);return}y(R=>R.map(s=>s.id===t?{...s,is_active:r}:s))},[l,a]=v.useState(null),n=async t=>{const{error:r}=await f.from("scheduled_reports").delete().eq("id",t);if(r){b.error("Failed to delete schedule: "+r.message);return}b.success("Schedule deleted"),a(null),i()};return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsxs("h2",{className:"text-xl font-semibold flex items-center gap-2",children:[e.jsx(se,{className:"h-5 w-5"}),"Scheduled Reports"]}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Automated report delivery to your team"})]}),e.jsxs(p,{size:"sm",onClick:()=>{$(null),w({name:"",report_type:"",schedule:"",recipients:"",delivery_format:"inline"}),C(!0)},children:[e.jsx(fe,{className:"h-4 w-4 mr-1"}),"New Schedule"]})]}),j?e.jsx(U,{className:"animate-pulse",children:e.jsx(O,{className:"p-8",children:e.jsx("div",{className:"h-16 bg-muted rounded"})})}):h.length===0?e.jsx(U,{children:e.jsxs(O,{className:"py-12 text-center",children:[e.jsx(se,{className:"h-10 w-10 mx-auto mb-3 text-muted-foreground opacity-50"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"No scheduled reports"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"Set up automated reports delivered to your inbox"})]})}):e.jsx("div",{className:"space-y-3",children:h.map(t=>e.jsx(U,{className:t.is_active?"":"opacity-60",children:e.jsx(O,{className:"p-4",children:e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsx(Pe,{checked:t.is_active,onCheckedChange:r=>m(t.id,r)}),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 text-sm",children:t.name}),e.jsx(je,{variant:"outline",className:"text-caption",children:oe.find(r=>r.value===t.report_type)?.label||t.report_type})]}),e.jsxs("div",{className:"flex items-center gap-3 mt-1 text-xs text-muted-foreground",children:[e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx(ne,{className:"h-3 w-3"}),ce.find(r=>r.value===t.schedule)?.label||t.schedule]}),e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx(ze,{className:"h-3 w-3"}),(t.recipients||[]).length," recipient",(t.recipients||[]).length!==1?"s":""]}),t.last_sent_at&&e.jsxs("span",{children:["Last: ",new Date(t.last_sent_at).toLocaleDateString()]})]})]}),e.jsxs("div",{className:"flex gap-1",children:[e.jsx(p,{variant:"ghost",size:"sm",className:"h-7 w-7 p-0",title:"Run now",onClick:()=>D(t.id),disabled:T===t.id,children:T===t.id?e.jsx(K,{className:"h-3 w-3 animate-spin"}):e.jsx(ve,{className:"h-3 w-3"})}),e.jsx(p,{variant:"ghost",size:"sm",className:"h-7 w-7 p-0",onClick:()=>{$(t.id),w({name:t.name,report_type:t.report_type,schedule:t.schedule,recipients:(t.recipients||[]).join(", "),delivery_format:t.config?.delivery_format||"inline"}),C(!0)},children:e.jsx(Be,{className:"h-3 w-3"})}),e.jsx(p,{variant:"ghost",size:"sm",className:"h-7 w-7 p-0 text-destructive",onClick:()=>a(t.id),children:e.jsx(ge,{className:"h-3 w-3"})})]})]})})},t.id))})]}),e.jsx(Q,{open:N,onOpenChange:C,children:e.jsxs(W,{children:[e.jsx(Y,{children:e.jsx(X,{children:_?"Edit Schedule":"New Scheduled Report"})}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx(P,{children:"Name"}),e.jsx(G,{value:o.name,onChange:t=>w(r=>({...r,name:t.target.value})),placeholder:"e.g. Weekly Utilization Report"})]}),e.jsxs("div",{children:[e.jsx(P,{children:"Report Type"}),e.jsxs(M,{value:o.report_type,onValueChange:t=>w(r=>({...r,report_type:t})),children:[e.jsx(I,{children:e.jsx(V,{placeholder:"Select report"})}),e.jsx(A,{children:oe.map(t=>e.jsx(F,{value:t.value,children:t.label},t.value))})]})]}),e.jsxs("div",{children:[e.jsx(P,{children:"Frequency"}),e.jsxs(M,{value:o.schedule,onValueChange:t=>w(r=>({...r,schedule:t})),children:[e.jsx(I,{children:e.jsx(V,{placeholder:"Select frequency"})}),e.jsx(A,{children:ce.map(t=>e.jsx(F,{value:t.value,children:t.label},t.value))})]})]}),e.jsxs("div",{children:[e.jsx(P,{children:"Recipients (comma-separated emails)"}),e.jsx(G,{value:o.recipients,onChange:t=>w(r=>({...r,recipients:t.target.value})),placeholder:"[email protected], [email protected]"})]}),e.jsxs("div",{children:[e.jsx(P,{children:"Delivery Format"}),e.jsxs(M,{value:o.delivery_format||"inline",onValueChange:t=>w(r=>({...r,delivery_format:t})),children:[e.jsx(I,{children:e.jsx(V,{placeholder:"Select format"})}
13),e.jsxs(A,{children:[e.jsx(F,{value:"inline",children:"Inline in email body"}),e.jsx(F,{value:"csv_attachment",children:"CSV attachment"}),e.jsx(F,{value:"both",children:"Both inline + CSV"})]})]})]})]}),e.jsxs(te,{children:[e.jsx(p,{variant:"outline",onClick:()=>C(!1),children:"Cancel"}),e.jsx(p,{onClick:u,children:_?"Update":"Create"})]})]})}),e.jsx(Q,{open:!!l,onOpenChange:()=>a(null),children:e.jsxs(W,{children:[e.jsx(Y,{children:e.jsx(X,{children:"Delete Schedule"})}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Are you sure you want to delete this scheduled report? This action cannot be undone."}),e.jsxs(te,{children:[e.jsx(p,{variant:"outline",onClick:()=>a(null),children:"Cancel"}),e.jsx(p,{variant:"destructive",onClick:()=>l&&n(l),children:"Delete"})]})]})})]})}const de=[{value:"executive_summary",label:"Executive Summary",desc:"Active projects, outstanding AR, pipeline value"},{value:"utilization",label:"Utilization",desc:"Hours, billable %, and capacity by person (30d)"},{value:"margin",label:"Margin & Burn",desc:"Budget vs. spend and margin on active projects"},{value:"pipeline",label:"Pipeline",desc:"Open proposals by stage and value"},{value:"ar_aging",label:"AR Aging",desc:"Outstanding invoices bucketed by days overdue"},{value:"revenue_by_client",label:"Revenue by Client",desc:"Paid revenue per client (90d)"},{value:"project_health",label:"Project Health",desc:"Completion vs. budget burn on active projects"},{value:"time_by_project",label:"Time by Project",desc:"Hours logged per project (30d)"}];function Ae(d){const h=y=>{const j=y==null?"":String(y);return/[",\n]/.test(j)?`"${j.replace(/"/g,'""')}"`:j};return d.map(y=>[y.title,y.columns.map(h).join(","),...y.rows.map(j=>y.columns.map(S=>h(j[S])).join(","))].join(` 14`)).join(` 15 16`)}function He(){const{currentTenant:d}=le(),{user:h}=_e(),y=qe(),[j,S]=v.useState(!1),[N,C]=v.useState([]),[_,$]=v.useState({name:"",description:""}),[o,w]=v.useState(null),[T,z]=v.useState(null),[D,i]=v.useState(null),{data:u=[],isLoading:m}=Ue({queryKey:["block-reports",d?.id],queryFn:async()=>{const{data:s,error:c}=await f.from("saved_reports").select("id, name, description, data_sources, last_run_at, created_at").eq("tenant_id",d.id).eq("report_type","blocks").order("created_at",{ascending:!1});if(c&&c.code!=="42P01")throw c;return s||[]},enabled:!!d?.id}),l=async(s,c,k)=>{if(d?.id){z(k||"adhoc");try{const{data:x,error:B}=await f.functions.invoke("execute-scheduled-reports",{body:{action:"run_blocks",tenant_id:d.id,blocks:c}});if(B||x?.error){b.error("Failed to run report: "+(x?.error||B?.message));return}w({name:s,blocks:x.blocks}),k&&(await f.from("saved_reports").update({last_run_at:new Date().toISOString()}).eq("id",k),y.invalidateQueries({queryKey:["block-reports"]}))}catch{b.error("Failed to run report")}finally{z(null)}}},a=re({mutationFn:async()=>{const{error:s}=await f.from("saved_reports").insert({tenant_id:d.id,created_by:h?.id,name:_.name,description:_.description||null,report_type:"blocks",data_sources:N,columns:[],filters:{}});if(s)throw s},onSuccess:()=>{y.invalidateQueries({queryKey:["block-reports"]}),S(!1),$({name:"",description:""}),C([]),b.success("Report saved")},onError:()=>b.error("Failed to save report")}),n=re({mutationFn:async s=>{const{error:c}=await f.from("saved_reports").delete().eq("id",s);if(c)throw c},onSuccess:()=>{y.invalidateQueries({queryKey:["block-reports"]}),b.success("Report deleted")}}),t=s=>{C(c=>c.includes(s)?c.filter(k=>k!==s):[...c,s])},r=()=>{if(!o)return;const s=Ae(o.blocks),c=new Blob([s],{type:"text/csv"}),k=URL.createObjectURL(c),x=document.createElement("a");x.href=k,x.download=`${o.name.replace(/[^a-z0-9-_ ]/gi,"")}-${Date.now()}.csv`,x.click(),URL.revokeObjectURL(k),b.success("Report exported as CSV")},g=()=>{if(!o)return;const s=window.open("","_blank");if(!s){b.error("Pop-up blocked â allow pop-ups to export PDF");return}const c=x=>String(x??"â").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">"),k=o.blocks.map(x=>` 17 <h2>${c(x.title)}</h2> 18 <table> 19 <thead><tr>${x.columns.map(B=>`<th>${c(B)}</th>`).join("")}</tr></thead> 20 <tbody>${x.rows.length===0?`<tr><td colspan="${x.columns.length}">No data</td></tr>`:x.rows.map(B=>`<tr>${x.columns.map(be=>`<td>${c(B[be])}</td>`).join("")}</tr>`).join("")}</tbody> 21 </table>`).join("");s.document.write(` 22 <html><head><title>${c(o.name)}</title> 23 <style> 24 body { font-family: -apple-system, BlinkMacSystemFont, sans-serif; padding: 24px; } 25 table { border-collapse: collapse; width: 100%; font-size: 12px; margin-bottom: 24px; } 26 th, td { border: 1px solid #ddd; padding: 6px 8px; text-align: left; } 27 th { background: #f5f5f5; font-weight: 600; } 28 tr:nth-child(even) { background: #fafafa; } 29 h1 { font-size: 18px; margin-bottom: 4px; } 30 h2 { font-size: 14px; margin: 16px 0 8px; } 31 .meta { color: #666; font-size: 12px; margin-bottom: 16px; } 32 </style></head><body> 33 <h1>${c(o.name)}</h1> 34 <div class="meta">${new Date().toLocaleDateString()}</div> 35 ${k} 36 <script>window.onload=function(){window.print();}<\/script> 37 </body></html>`),s.document.close(),b.success("Print dialog opened â choose 'Save as PDF'")},R=async s=>{if(o){i(s);try{s==="docx"?await Le(o.name,o.blocks):await Ee(o.name,o.blocks),b.success(`Report exported as ${s.toUpperCase()}`)}catch(c){b.error(`Failed to export ${s.toUpperCase()}: `+(c instanceof Error?c.message:"unknown error"))}finally{i(null)}}};return e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-medium",children:"Report Builder"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Compose reports from analytics blocks â utilization, margin, pipeline, AR aging, and more"})]}),e.jsxs(p,{onClick:()=>S(!0),size:"sm",children:[e.jsx(fe,{className:"h-4 w-4 mr-1"}),"New Report"]})]}),m?e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading reports..."}):u.length===0?e.jsx(U,{children:e.jsxs(O,{className:"py-8 text-center",children:[e.jsx(ae,{className:"h-8 w-8 text-muted-foreground
37/40 mx-auto mb-3"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"No saved reports yet"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"Compose your first report from analytics blocks"})]})}):e.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-3",children:u.map(s=>e.jsx(U,{children:e.jsx(O,{className:"py-3 px-4",children:e.jsxs("div",{className:"flex items-start justify-between",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ae,{className:"h-4 w-4 text-primary shrink-0"}),e.jsx("p",{className:"text-sm font-medium truncate",children:s.name})]}),s.description&&e.jsx("p",{className:"text-xs text-muted-foreground mt-1 line-clamp-1",children:s.description}),e.jsx("div",{className:"flex items-center gap-1 mt-2 flex-wrap",children:s.data_sources.map(c=>e.jsx(je,{variant:"outline",className:"text-caption",children:de.find(k=>k.value===c)?.label||c},c))}),s.last_run_at&&e.jsxs("p",{className:"text-caption text-muted-foreground mt-1 flex items-center gap-1",children:[e.jsx(ne,{className:"h-2.5 w-2.5"}),"Last run: ",Me(new Date(s.last_run_at),"MMM d, h:mm a")]})]}),e.jsxs("div",{className:"flex gap-1 shrink-0 ml-2",children:[e.jsx(p,{variant:"ghost",size:"icon",className:"h-7 w-7",title:"Run report",onClick:()=>l(s.name,s.data_sources,s.id),disabled:T===s.id,children:T===s.id?e.jsx(K,{className:"h-3.5 w-3.5 animate-spin"}):e.jsx(ve,{className:"h-3.5 w-3.5"})}),e.jsx(p,{variant:"ghost",size:"icon",className:"h-7 w-7 text-destructive",onClick:()=>n.mutate(s.id),"aria-label":"Delete",children:e.jsx(ge,{className:"h-3.5 w-3.5"})})]})]})})},s.id))}),e.jsx(Q,{open:j,onOpenChange:S,children:e.jsxs(W,{className:"max-w-lg",children:[e.jsxs(Y,{children:[e.jsx(X,{children:"New Block Report"}),e.jsx(ie,{children:"Pick the analytics blocks to include. Each block renders as a section."})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx(P,{children:"Report Name"}),e.jsx(G,{value:_.name,onChange:s=>$({..._,name:s.target.value}),placeholder:"e.g., Monday Ops Review"})]}),e.jsxs("div",{children:[e.jsx(P,{children:"Description"}),e.jsx(G,{value:_.description,onChange:s=>$({..._,description:s.target.value}),placeholder:"Optional"})]}),e.jsxs("div",{children:[e.jsx(P,{className:"mb-2 block",children:"Blocks"}),e.jsx("div",{className:"space-y-2 max-h-64 overflow-y-auto",children:de.map(s=>e.jsxs("label",{className:"flex items-start gap-2 text-sm cursor-pointer",children:[e.jsx(Oe,{checked:N.includes(s.value),onCheckedChange:()=>t(s.value),className:"mt-0.5"}),e.jsxs("span",{children:[s.label,e.jsx("span",{className:"block text-xs text-muted-foreground",children:s.desc})]})]},s.value))})]})]}),e.jsxs(te,{children:[e.jsx(p,{variant:"outline",onClick:()=>S(!1),children:"Cancel"}),e.jsx(p,{variant:"secondary",onClick:()=>{S(!1),l(_.name||"Ad-hoc Report",N)},disabled:N.length===0||T==="adhoc",children:"Run Once"}),e.jsx(p,{onClick:()=>a.mutate(),disabled:!_.name||N.length===0||a.isPending,children:"Save Report"})]})]})}),e.jsx(Q,{open:!!o,onOpenChange:s=>!s&&w(null),children:e.jsxs(W,{className:"max-w-4xl max-h-[85vh] overflow-y-auto",children:[e.jsx(Y,{children:e.jsxs("div",{className:"flex items-center justify-between pr-6",children:[e.jsxs("div",{children:[e.jsx(X,{children:o?.name}),e.jsxs(ie,{children:[o?.blocks.length||0," block",(o?.blocks.length||0)!==1?"s":""]})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs(p,{variant:"outline",size:"sm",onClick:r,children:[e.jsx(pe,{className:"h-3.5 w-3.5 mr-1"}),"CSV"]}),e.jsxs(p,{variant:"outline",size:"sm",onClick:g,children:[e.jsx(H,{className:"h-3.5 w-3.5 mr-1"}),"PDF"]}),e.jsxs(p,{variant:"outline",size:"sm",onClick:()=>R("docx"),disabled:D!==null,children:[D==="docx"?e.jsx(K,{className:"h-3.5 w-3.5 mr-1 animate-spin"}):e.jsx(H,{className:"h-3.5 w-3.5 mr-1"}),"DOCX"]}),e.jsxs(p,{variant:"outline",size:"sm",onClick:()=>R("pptx"),disabled:D!==null,children:[D==="pptx"?e.jsx(K,{className:"h-3.5 w-3.5 mr-1 animate-spin"}):e.jsx(H,{className:"h-3.5 w-3.5 mr-1"}),"PPTX"]}
37)]})]})}),e.jsx("div",{className:"space-y-6",children:o?.blocks.map(s=>e.jsxs("div",{children:[e.jsx("h4",{className:"font-medium text-sm mb-2",children:s.title}),s.rows.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"No data"}):e.jsx("div",{className:"overflow-x-auto border rounded-md",children:e.jsxs(ue,{children:[e.jsx(me,{children:e.jsx(J,{children:s.columns.map(c=>e.jsx(L,{className:"text-xs whitespace-nowrap",children:c.replace(/_/g," ")},c))})}),e.jsx(he,{children:s.rows.map((c,k)=>e.jsx(J,{children:s.columns.map(x=>e.jsx(E,{className:"text-xs",children:c[x]!=null?String(c[x]):"â"},x))},k))})]})})]},s.key))})]})})]})}function wt(){return e.jsx("div",{className:"p-6 max-w-7xl mx-auto space-y-6",children:e.jsxs(we,{defaultValue:"reports",children:[e.jsxs(Ne,{children:[e.jsxs(Z,{value:"reports",className:"flex items-center gap-1",children:[e.jsx(xe,{className:"h-4 w-4"}),"Reports"]}),e.jsxs(Z,{value:"builder",className:"flex items-center gap-1",children:[e.jsx(ae,{className:"h-4 w-4"}),"Builder"]}),e.jsxs(Z,{value:"scheduled",className:"flex items-center gap-1",children:[e.jsx(se,{className:"h-4 w-4"}),"Scheduled"]})]}),e.jsx(ee,{value:"reports",className:"mt-4",children:e.jsx(Ie,{})}),e.jsx(ee,{value:"builder",className:"mt-4",children:e.jsx(He,{})}),e.jsx(ee,{value:"scheduled",className:"mt-4",children:e.jsx(Ve,{})})]})})}export{wt 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.