1import{d3 as le,j as a,d4 as ie,dy as ce,dz as de,dr as me,eg as ue,d7 as pe,eh as xe,ei as he,dE as fe,r as i,c_ as be,b4 as je,b3 as ve,bN as D,bO as $,L as W,ao as ge,bP as K,bT as ye,as as J,J as we,Y as _e,b as Ne,bf as Pe,b9 as V,aI as l,cf as ke,cg as Ce,ch as Se,ci as Ee,cj as g}from"./index-CpeGhXo5.js";import{F as Ae}from"./FilterBar-B_jdgGzl.js";import{u as Te}from"./useCurrencyHelpers-D5hUvgaW.js";import{u as y}from"./useGlobalFilter-BkOUrZeG.js";import{a as Le}from"./EntityPill-btGCy98_.js";import{c as Fe,g as Re,m as Me}from"./financeMappers-CUv1G2pV.js";import{I as Ie}from"./ImportExportMenu-h8yJbDMc.js";import{b as De,E as O,a as B,s as G}from"./excelUtils-B6c4w-tr.js";import"./filters-DQMtevU2.js";import"./mock-Ci00pIzy.js";import"./currency-CACMzR5Q.js";function qe(){const u=le();return u||a.jsx($e,{})}function $e(){const u=ie(),{fmtConv:d}=Te(),{data:w=[],isLoading:h,isFetching:Q,error:_,refetch:N}=ce(),{data:P}=de({limit:1e3}),{data:k}=me({limit:2e3}),{data:C}=ue({limit:2e3}),{data:S}=pe({limit:2e3}),[E]=xe(),[z]=he(),[H]=fe(),[U,A]=i.useState([]),[x,Y]=i.useState("all"),[q,T]=i.useState(!1),{data:X=[]}=be(),[L,F]=i.useState(()=>{try{const e=localStorage.getItem("approved_project_profitability_ids");return e?new Set(JSON.parse(e)):new Set}catch{return new Set}});i.useEffect(()=>{const e=()=>{try{const t=localStorage.getItem("approved_project_profitability_ids");t&&F(new Set(JSON.parse(t)))}catch{}};return window.addEventListener("storage",e),window.addEventListener("finance-project-approved",e),()=>{window.removeEventListener("storage",e),window.removeEventListener("finance-project-approved",e)}},[]);const Z=async(e,t)=>{F(r=>{const s=new Set(r);s.add(e);try{localStorage.setItem("approved_project_profitability_ids",JSON.stringify(Array.from(s))),window.dispatchEvent(new Event("finance-project-approved"))}catch{}return s});try{e&&!e.startsWith("rev-proj-")&&!e.startsWith("inv-proj-")&&await H({id:e,body:{status:"Approved"}}).unwrap()}catch{}l.success(`Project "${t}" audited & approved by CFO (Pawandeep Kaur)!`)},ee=i.useMemo(()=>(k?.items??[]).map(Fe),[k]),te=i.useMemo(()=>(C?.items??[]).map(Re),[C]),ae=i.useMemo(()=>(S?.items??[]).map(Me),[S]),f=y(ee,"date"),b=y(te,"date"),R=y(ae,"date"),j=i.useMemo(()=>{const e=new Map;return w.forEach(t=>{const r=(t.project_name||t.name||"").trim();if(!r)return;const s=Number(t.direct_cost??t.cost??0),o=Number(t.direct_revenue??t.revenue??0);e.set(r.toLowerCase(),{id:t.id,project_name:r,client_name:t.client_name||"Client",company_name:t.company_name||"Tekki Web Solutions Pvt. Ltd.",budget:Number(t.budget||0),direct_cost:s,direct_revenue:o,total_revenue:o,total_cost:s,status:t.status||"Pending Approval"})}),(P?.items??[]).forEach(t=>{const r=(t.name||"").trim();if(!r)return;const s=r.toLowerCase(),o=e.get(s),p=Number(t.cost??0),c=Number(t.revenue??0);o?(o.id=t.id,o.direct_cost=p,o.direct_revenue=c,t.budget!=null&&(o.budget=Number(t.budget)),t.clientName&&(o.client_name=t.clientName),t.teamName&&(o.company_name=t.teamName),t.status&&(o.status=t.status)):e.set(s,{id:t.id,project_name:r,client_name:t.clientName||"Client",company_name:t.teamName||"Tekki Web Solutions Pvt. Ltd.",budget:Number(t.budget||0),direct_cost:p,direct_revenue:c,total_revenue:c,total_cost:p,status:t.status||"In Progress"})}),f.forEach(t=>{if(!t.project)return;const r=t.project.trim(),s=r.toLowerCase();e.has(s)||e.set(s,{id:`rev-proj-${s}`,project_name:r,client_name:t.client||"Client",company_name:t.company||"Tekki Web Solutions Pvt. Ltd.",budget:t.gross||0,direct_cost:0,direct_revenue:0,total_revenue:0,total_cost:0})}),b.forEach(t=>{if(!t.project)return;const r=t.project.trim(),s=r.toLowerCase();e.has(s)||e.set(s,{id:`inv-proj-${s}`,project_name:r,client_name:t.client||"Client",company_name:"Tekki Web Solutions Pvt. Ltd.",budget:t.amount||0,direct_cost:0,direct_revenue:0,total_revenue:0,total_cost:0})}),Array.from(e.values()).map(t=>{const r=t.project_name.toLowerCase(),s=f.filter(n=>n.project&&n.project.toLowerCase().trim()===r).reduce((n,m)=>n+(m.gross||0),0),o=b.filter(n=>n.project&&(n.project.toLowerCase().trim()===r||n.project.toLowerCase().includes(r))).reduce((n,m)=>n+(m.amount||0),0),p=s+o,c=p>0?p:Number(t.direct_revenue||0),M=R.filter(n=>(n.project||"").toLowerCase().trim()===r).reduce((n,m)=>n+(m.net||m.gross||m.amount||0),0)+Number(t.direct_cost||0),I=c-M,ne=c>0?I/c*100:0;return{...t,total_revenue:c,total_cost:M,profit:I,margin_pct:ne}})},[w,P,f,b,R]),v=i.useMemo(()=>x==="all"?j:j.filter(e=>e.company_name===x),[j,x]),re=async()=>{try{const e=new O.Workbook,t=v.map(r=>({"Project Name":r.project_name||"",Client:r.client_name||"",Company:r.company_name||"",Budget:r.budget||0,"Total Revenue":r.total_revenue||0,"Total Cost":r.total_cost||0,"Profit Margin (%)":r.total_revenue>0?((r.total_revenue-r.total_cost)/r.total_revenue*100).toFixed(2):0}));B(e,t,"Project Profitability"),await G(e,"ProjectProfitability_Export"),l.success("Projects exported successfully.")}catch{l.error("Failed to export projects.")}},se=async()=>{try{const e=new O.Workbook;
1B(e,[{"Project Name":"Alpha Redesign",Client:"Acme Corp",Company:"Tekki Web Solutions Pvt. Ltd.",Budget:5e5,"Start Date":"Jan 2026","End Date":"Dec 2026",Status:"Active",Team:"MERN Stack"}],"Import Template"),await G(e,"Project_Import_Template"),l.success("Sample template downloaded.")}catch{l.error("Failed to download template.")}},oe=async e=>{try{const t=await De(e);if(t.length===0){l.error("No valid data found in file.");return}let r=0;for(const s of t){const o=s["Project Name"]||s.Project||s.project_name||s.Name||s["PROJECT NAME"];o&&(await z({name:o,clientName:s.Client||s["Client Name"]||s.client_name||"",companyName:s.Company||s["Company Name"]||"",budget:Number(s.Budget||s["Client Budget"]||0),startLabel:s["Start Date"]||"Jan 2026",endLabel:s["End Date"]||"Dec 2026",status:s.Status||"Active",teamName:s.Team||s.Company||"Unknown Team"}).unwrap(),r++)}await N(),r===0?l.error(`Import failed. Found 0 valid projects in the ${t.length} rows. Please check your column headers.`):l.success(`Successfully imported ${r} projects.`)}catch(t){l.error(t.message||"Failed to import projects.")}};return a.jsxs("div",{className:"flex flex-col flex-1 h-full min-h-0 overflow-hidden bg-slate-50/50",children:[a.jsx(je,{title:"Project Profitability",subtitle:`${v.length} projects`,accentVar:"--mod-project",showMonthYearFilter:!1}),a.jsx("div",{className:"shrink-0 bg-surface/50 border-b border-border px-4 py-2 flex items-center justify-between flex-wrap gap-2",children:a.jsx(Ae,{showMonths:!0,actions:a.jsxs("div",{className:"flex items-center gap-1.5",children:[a.jsx(Ie,{onDownloadSample:se,onExport:re,onImport:oe}),a.jsx(ve,{delayDuration:150,children:a.jsxs(D,{children:[a.jsx($,{asChild:!0,children:a.jsx(W,{to:`${u}/project-profitability/new`,className:"h-8 w-8 p-0 rounded-lg bg-blue-600 hover:bg-blue-700 text-white inline-flex items-center justify-center shadow-2xs transition-colors shrink-0 cursor-pointer",children:a.jsx(ge,{className:"w-4 h-4"})})}),a.jsx(K,{side:"bottom",align:"end",children:a.jsx("p",{children:"Add Project"})})]})})]})})}),a.jsxs("div",{className:"p-3 pb-3 flex-1 min-h-0 flex flex-col overflow-hidden",children:[_&&a.jsxs("div",{className:"bg-red-50 text-red-500 p-4 rounded-md mb-2",children:[a.jsx("p",{className:"font-bold",children:"Error loading projects:"}),a.jsx("pre",{className:"text-xs",children:JSON.stringify(_,null,2)})]}),a.jsx(ye,{searchKeys:["project_name","client_name","company_name"],searchPlaceholder:"Search projectsâ¦",toolbar:a.jsx("div",{className:"flex items-center gap-1.5 shrink-0",children:a.jsxs(ke,{value:x,onValueChange:Y,children:[a.jsx(Ce,{className:"h-8 w-[160px] text-xs rounded-[5px] border border-border bg-background shadow-sm",children:a.jsx(Se,{placeholder:"All Companies"})}),a.jsxs(Ee,{className:"text-xs",children:[a.jsx(g,{value:"all",children:"All Companies"}),(()=>{const e=new Set(["ABS Technology","Bright Media","Logicreators","Pawandeep Kaur","Sarbjit Singh","TekkizQA Stack","TWS"]),t=X.filter(r=>!e.has(r.name));return t.length===0?a.jsx(g,{value:"Tekki Web Solutions Pvt. Ltd.",children:"Tekki Web Solutions Pvt. Ltd."},"default"):t.map(r=>a.jsx(g,{value:r.name,children:r.name},r.id))})()]})]})}),selectable:!0,selectedIds:U,onSelectionChange:A,bulkActions:[{id:"delete",label:"Delete",icon:a.jsx(V,{className:"w-3.5 h-3.5"}),variant:"destructive",onAction:async e=>{if(confirm(`Delete ${e.length} selected project(s)?`)){for(const t of e)try{await E(t.id).unwrap()}catch{}l.success(`Deleted ${e.length} project(s)`),A([])}}}],rows:h?[]:v,rowKey:e=>e.id,storageKey:"project-profitability",initialPageSize:25,loading:h,fetching:Q||h||q,empty:"No projects found",fillHeight:!0,onRefresh:async()=>{T(!0),await N(),setTimeout(()=>T(!1),500)},columns:[{key:"project_name",label:"Project Name",sortable:!0,render:e=>a.jsx("div",{className:"font-semibold text-foreground truncate",children:e.project_name})},{key:"client_name",label:"Client",width:"150px",sortable:!0,render:e=>a.jsx("span",{className:"text-xs text-muted-foreground",children:e.client_name||"â"})},{key:"company_name",label:"Company",width:"190px",sortable:!0,render:e=>a.jsx(Le,{name:e.company_name})},{key:"budget",label:"Budget",width:"120px",align:"right",sortable:!0,sortValue:e=>e.budget||0,render:e=>a.jsx("span",{className:"font-data font-semibold text-xs text-foreground",children:d(e.budget||0)})},{key:"rev",label:"Revenue",width:"120px",align:"right",sortable:!0,sortValue:e=>e.total_revenue||0,render:e=>a.jsx("span",{className:"font-data text-xs text-foreground",children:d(e.total_revenue||0)})},{key:"exp",label:"Expenses",width:"120px",align:"right",sortable:!0,sortValue:e=>e.total_cost||0,render:e=>a.jsx("span",{className:"font-data text-xs text-muted-foreground",children:d(e.total_cost||0)})},{key:"profit",label:"Profit / Loss",width:"130px",align:"right",sortable:!0,sortValue:e=>e.total_revenue-e.total_cost||0,render:e=>{const t=e.total_revenue-e.total_cost;return a.jsx("span",{className:J("font-data font-semibold text-xs",t>=0?"text-emerald-600":"text-rose-600"),children:d(t)})}},{key:"margin",label:"Margin %",width:"100px",align:"right",sortable:!0,sortValue:e=>e.total_revenue>0?(e.total_revenue-e.total_cost)/e.total_revenue*100:0,render:e=>{const t=e.total_revenue>0?(e.total_revenue-e.total_cost)/e.total_revenue*100:0;
1return a.jsxs("span",{className:`font-data font-semibold ${t>=0?"text-emerald-600":"text-rose-600"}`,children:[t.toFixed(1),"%"]})}},{key:"performance",label:"Performance Chart",width:"150px",align:"center",sortable:!1,render:e=>{const t=Math.max(e.total_revenue,e.total_cost,1),r=e.total_revenue/t*100,s=e.total_cost/t*100;return a.jsx("div",{className:"w-full flex flex-col justify-center px-1 py-1 group cursor-pointer",children:a.jsxs(D,{children:[a.jsx($,{asChild:!0,children:a.jsxs("div",{className:"flex flex-col gap-1 w-full",children:[a.jsxs("div",{className:"flex items-center gap-1.5 w-full",children:[a.jsx("span",{className:"text-[8px] font-bold text-muted-foreground w-6 text-left leading-none",children:"REV"}),a.jsx("div",{className:"h-1.5 flex-1 bg-muted/60 rounded-full overflow-hidden",children:a.jsx("div",{className:"h-full bg-emerald-500 rounded-full transition-all duration-300 group-hover:brightness-95",style:{width:`${r}%`}})})]}),a.jsxs("div",{className:"flex items-center gap-1.5 w-full",children:[a.jsx("span",{className:"text-[8px] font-bold text-muted-foreground w-6 text-left leading-none",children:"CST"}),a.jsx("div",{className:"h-1.5 flex-1 bg-muted/60 rounded-full overflow-hidden",children:a.jsx("div",{className:"h-full bg-rose-500 rounded-full transition-all duration-300 group-hover:brightness-95",style:{width:`${s}%`}})})]})]})}),a.jsxs(K,{side:"top",className:"p-2 min-w-[130px] font-sans text-xs flex flex-col gap-1 z-[150] bg-slate-950 border-slate-800 text-white shadow-xl rounded-lg",children:[a.jsxs("div",{className:"flex justify-between gap-4 items-center",children:[a.jsx("span",{className:"text-slate-400 font-medium",children:"Revenue:"}),a.jsx("span",{className:"font-mono font-bold text-emerald-400",children:d(e.total_revenue)})]}),a.jsxs("div",{className:"flex justify-between gap-4 items-center",children:[a.jsx("span",{className:"text-slate-400 font-medium",children:"Cost:"}),a.jsx("span",{className:"font-mono font-bold text-rose-400",children:d(e.total_cost)})]}),a.jsx("div",{className:"border-t border-slate-800 my-1"}),a.jsxs("div",{className:"flex justify-between gap-4 items-center",children:[a.jsx("span",{className:"text-slate-400 font-medium",children:"Profit:"}),a.jsx("span",{className:J("font-mono font-bold",e.total_revenue-e.total_cost>=0?"text-emerald-400":"text-rose-400"),children:d(e.total_revenue-e.total_cost)})]})]})]})})}},{key:"status",label:"Approval Status",width:"145px",sortable:!0,render:e=>L.has(e.id)||e.status==="Approved"?a.jsxs("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-[10px] font-bold bg-emerald-50 text-emerald-700 dark:bg-emerald-950/50 dark:text-emerald-300 border border-emerald-200 dark:border-emerald-800",children:[a.jsx(we,{className:"w-3 h-3 text-emerald-600 shrink-0"})," Approved"]}):a.jsxs("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-[10px] font-bold bg-amber-50 text-amber-700 dark:bg-amber-950/50 dark:text-amber-300 border border-amber-200 dark:border-amber-800",children:[a.jsx(_e,{className:"w-3 h-3 text-amber-600 shrink-0"})," Pending Approval"]})},{key:"actions",label:"ACTIONS",width:"110px",sortable:!1,fixed:"right",render:e=>{const t=L.has(e.id)||e.status==="Approved";return a.jsxs("div",{className:"flex items-center gap-1 justify-center",onClick:r=>r.stopPropagation(),children:[!t&&a.jsx("button",{type:"button",onClick:()=>Z(e.id,e.project_name),className:"p-1 rounded bg-emerald-50 hover:bg-emerald-100 text-emerald-700 dark:bg-emerald-950/50 dark:hover:bg-emerald-900/60 dark:text-emerald-300 transition-colors cursor-pointer",title:"Audit & Approve by CFO (Pawandeep Kaur)",children:a.jsx(Ne,{className:"w-3.5 h-3.5 text-emerald-600"})}),a.jsx(W,{to:`${u}/project-profitability/new?editId=${e.id}`,className:"p-1 rounded hover:bg-primary/10 hover:text-primary transition-colors cursor-pointer",title:"Edit Project",children:a.jsx(Pe,{className:"w-3.5 h-3.5"})}),a.jsx("button",{type:"button",onClick:async()=>{confirm("Are you sure you want to delete this project?")&&(await E(e.id).unwrap(),l.success("Project deleted successfully"))},className:"p-1 rounded hover:bg-rose-50 text-slate-600 hover:text-rose-600 transition-colors cursor-pointer",title:"Delete Project",children:a.jsx(V,{className:"w-3.5 h-3.5"})})]})}}],onRowClick:e=>navigate(`${u}/project-profitability/new?editId=${e.id}`)})]})]})}export{qe as ProjectProfitabilityPage,qe 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.