1import{r as g,j as e}from"./vendor-react-DKbe1Umz.js";import{u as re,q as p,o as b,D as le,Z as oe,B as j,c as ce,d as me,e as ue,f as he,L as I,S as D,g as U,h as P,i as F,j as S,n as pe,b6 as Se,aF as fe,bg as xe,r as M,l as H,C as _,s as G,t as Z,v as W}from"./index-DZ74KeH3.js";import{u as T,a as C,d as be}from"./vendor-data-CjSe2wkl.js";import{R as Ce,a as ae}from"./radio-group-NU-uess9.js";import{b8 as Ie,c0 as K,c1 as $e,b6 as ie,dr as Ee,E as ne,cZ as Te,b3 as De,dE as Ue,cK as Pe,F as de}from"./vendor-ui-DMaW9-Ov.js";import{O as Fe}from"./ObjectUploader-BErHjEh8.js";import"./vendor-charts-DWX9qznF.js";import"./vendor-dates-5UNeOyFW.js";import"./vendor-forms-C2vWC2ab.js";function Le({sourceTakeoffId:v,measurementIds:i,bidId:u,projectId:N,triggerLabel:c}){const{toast:o}=re(),[k,y]=g.useState(!1),[h,w]=g.useState(""),[L,O]=g.useState("merge"),$=u?`/api/bids/${u}/estimates`:N?`/api/projects/${N}/estimates`:"/api/estimates",{data:A=[]}=T({queryKey:[$],enabled:k}),E=C({mutationFn:async()=>(await b("POST","/api/takeoff/send-to-estimate",{estimateId:h,sourceTakeoffId:v,measurementIds:i,mode:L})).json(),onSuccess:l=>{p.invalidateQueries({queryKey:[`/api/estimates/${h}/line-items`]}),o({title:"Sent to estimate",description:`${l.inserted??0} new, ${l.updated??0} updated, ${l.removed??0} removed.`}),y(!1)},onError:l=>o({title:"Send failed",description:l instanceof Error?l.message:"Unknown error",variant:"destructive"})});return e.jsxs(le,{open:k,onOpenChange:y,children:[e.jsx(oe,{asChild:!0,children:e.jsxs(j,{size:"sm",disabled:i.length===0,"data-testid":"button-send-to-estimate",children:[e.jsx(Ie,{className:"w-3.5 h-3.5 mr-1.5"}),c??"Send to estimate"]})}),e.jsxs(ce,{"data-testid":"dialog-send-to-estimate",children:[e.jsxs(me,{children:[e.jsxs(ue,{children:["Send ",i.length," measurements to estimate"]}),e.jsx(he,{children:"Re-sending the same measurements is safe â quantities and unit costs are updated in place; user-edited markup, labor, and notes are preserved."})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx(I,{children:"Estimate"}),e.jsxs(D,{value:h,onValueChange:w,children:[e.jsx(U,{"data-testid":"select-estimate",children:e.jsx(P,{placeholder:"Select estimate..."})}),e.jsx(F,{children:A.map(l=>e.jsx(S,{value:l.id,children:l.name||l.title||l.id},l.id))})]})]}),e.jsxs("div",{children:[e.jsx(I,{children:"Mode"}),e.jsxs(Ce,{value:L,onValueChange:l=>O(l),children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ae,{value:"merge",id:"mode-merge","data-testid":"radio-mode-merge"}),e.jsx(I,{htmlFor:"mode-merge",className:"font-normal",children:"Merge â update existing rows, add new ones"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ae,{value:"replace",id:"mode-replace","data-testid":"radio-mode-replace"}),e.jsx(I,{htmlFor:"mode-replace",className:"font-normal",children:"Replace â also remove any line items no longer in the selection"})]})]})]})]}),e.jsx(pe,{children:e.jsx(j,{onClick:()=>E.mutate(),disabled:!h||E.isPending,"data-testid":"button-confirm-send",children:E.isPending?e.jsx(K,{className:"w-4 h-4 animate-spin"}):"Send"})})]})]})}const q={G:"General",A:"Architectural",S:"Structural",M:"Mechanical",E:"Electrical",P:"Plumbing",C:"Civil",L:"Landscape",FP:"Fire Protection",T:"Telecom",Q:"Equipment",I:"Interiors",O:"Other"},J=Object.keys(q);function _e(){const[,v]=Se("/takeoff/standalone/:id"),i=(v==null?void 0:v.id)??"",{toast:u}=re(),[N,c]=g.useState(!1),[o,k]=g.useState("ALL"),y=T({queryKey:["/api/takeoff/standalone",i],enabled:!!i}),h=T({queryKey:["/api/takeoff/standalone",i,"sheets"],enabled:!!i}),w=T({queryKey:["/api/takeoff/standalone",i,"files"],enabled:!!i}),L=T({queryKey:["/api/takeoff/standalone",i,"tags"],enabled:!!i}),O=C({mutationFn:async t=>(await b("POST",`/api/takeoff/standalone/${i}/tags`,t)).json(),onSuccess:()=>{p.invalidateQueries({queryKey:["/api/takeoff/standalone",i,"tags"]}),u({title:"Tagged",description:"Takeoff linked successfully."}),c(!1)},onError:t=>u({title:"Tag failed",description:t instanceof Error?t.message:"Unknown error",variant:"destructive"})}),$=C({mutationFn:async t=>(await b("PATCH",`/api/takeoff/standalone/${i}/sheets/reorder`,{order:t})).json(),onMutate:async t=>{await p.cancelQueries({queryKey:["/api/takeoff/standalone",i,"sheets"]});const s=p.getQueryData(["/api/takeoff/standalone",i,"sheets"]);if(s){const n=new Map(t.map(a=>[a.id,a.sheetIndex])),r=[...s].map(a=>({...a,sheetIndex:n.get(a.id)??a.sheetIndex})).sort((a,d)=>a.sheetIndex-d.sheetIndex);p.setQueryData(["/api/takeoff/standalone",i,"sheets"],r)}return{previous:s}},onError:(t,s,n)=>{n!=null&&n.previous&&p.setQueryData(["/api/takeoff/standalone",i,"sheets"],n.previous),u({title:"Reorder failed",description:t instanceof Error?t.message:"Unknown error",variant:"destructive"})},onSettled:()=>{p.invalidateQueries({queryKey:["/api/takeoff/standalone",i,"sheets"]})}}),A=(t,s)=>{const n=h.data??[],r=n.findIndex(x=>x.id===t);if(r<0)return;const a=s==="up"?r-1:r+1;if(a<0||a>=n.length)return;const d=[...n];[d[r],d[a]]=[d[a],d[r]],$.mutate(d.map((x,B)=>({id:x.id,sheetIndex:B})))},E=C({mutationFn:async t=>(await b("PATCH",`/api/takeoff/standalone/${i}/sheets/${t.sheetId}/discipline`,{discipline:t.discipline})).json(),onSuccess:()=>{p.invalidateQueries({queryKey:["/api/takeoff/standalone",i,"sheets"]})},onError:t=>u({title:"Could not update discipline",description:t instanceof Error?t.message:"Unknown error",variant:"destructive"})}),l=C({mutationFn:async t=>{await b("DELETE",`/api/takeoff/standalone/${i}/tags/${t}`)},onSuccess:()=>{p.invalidateQueries({queryKey:["/api/takeoff/standalone",i,"tags"]})}}),{data:je=[]}=fe(),{data:ge=[]}=xe(),X=C({mutationFn:async t=>{var r;if(t.mimeType==="application/pdf"||/\.pdf$/i.test(t.fileName)){const d=await(await b("POST",`/api/takeoff/standalone/${i}/import-plan`,t)).json();return{pageCount:Number(d.pageCount??((r=d.sheets)==null?void 0:r.length)??1)}}if(await b("POST",`/api/takeoff/standalone/${i}/files`,t),t.mimeType.startsWith("image/")||/\.(png|jpe?g)$/i.test(t.fileName)){const a=t.fileName.replace(/\.[^/.]+$/,"");return await b("POST",`/api/takeoff/standalone/${i}/sheets`,{imageUrl:t.fileUrl,sheetName:a}),{pageCount:1}}return{pageCount:0}},onSuccess:()=>{p.invalidateQueries({queryKey:["/api/takeoff/standalone",i,"files"]}),p.invalidateQueries({queryKey:["/api/takeoff/standalone",i,"sheets"]})},onError:t=>u({title:"Upload failed",description:t instanceof Error?t.message:"Unknown error",variant:"destructive"})}),ve=t=>{var r;if(!((r=t.successful)!=null&&r.length)){u({title:"Upload failed",description:"No file uploaded",variant:"destructive"});return}let s=0,n=0;t.successful.forEach(a=>{var se;const d=a.data,x=(d==null?void 0:d.name)??a.name??"plan.pdf",B=(d==null?void 0:d.type)??a.type??"application/octet-stream",ke=(d==null?void 0:d.size)??a.size??0,z=(a.uploadURL??"").split("?")[0],ye=((se=a.meta)==null?void 0:se.objectKey)??z;z&&X.mutate({fileName:x,fileUrl:z,objectKey:ye,fileSize:ke,mimeType:B},{onSuccess:V=>{if(s+=1,n+=(V==null?void 0:V.pageCount)??0,s===t.successful.length){const we=n>s?` (${n} sheets)`:"";u({title:"Upload complete",description:`${s} file(s) attached to this takeoff${we}.`})}}})})},m=h.data??[],Q=g.useMemo(()=>{const t=new Map;for(const s of m){const n=s.discipline??"UNCLASSIFIED";
1t.set(n,(t.get(n)??0)+1)}return t},[m]),Ne=g.useMemo(()=>J.filter(t=>(Q.get(t)??0)>0),[Q]),Y=g.useMemo(()=>{const t=m.filter(a=>o==="ALL"?!0:o==="UNCLASSIFIED"?!a.discipline:a.discipline===o),s=new Map;for(const a of t){const d=a.discipline??"UNCLASSIFIED",x=s.get(d)??[];x.push(a),s.set(d,x)}for(const a of s.values())a.sort((d,x)=>d.sheetIndex-x.sheetIndex);const n=[];for(const a of J){const d=s.get(a);d&&d.length>0&&n.push({code:a,sheets:d})}const r=s.get("UNCLASSIFIED");return r&&r.length>0&&n.push({code:"UNCLASSIFIED",sheets:r}),n},[m,o]);if(!i)return e.jsx("div",{className:"p-6",children:"Missing takeoff id."});if(y.isLoading)return e.jsx("div",{className:"flex items-center justify-center py-16","data-testid":"standalone-loading",children:e.jsx(K,{className:"w-8 h-8 animate-spin text-muted-foreground"})});if(!y.data)return e.jsx("div",{className:"p-6",children:"Takeoff not found."});const f=y.data,R=w.data??[],ee=L.data??[],te=X.isPending;return e.jsxs("div",{className:"container max-w-full mx-auto p-6 space-y-6","data-testid":"standalone-takeoff-page",children:[e.jsx("div",{className:"flex items-center gap-2 text-sm text-muted-foreground",children:e.jsx(M,{href:"/takeoff","data-testid":"link-back-to-takeoff",children:e.jsxs("span",{className:"inline-flex items-center gap-1 hover:text-foreground",children:[e.jsx($e,{className:"w-4 h-4"})," All takeoffs"]})})}),e.jsxs("div",{className:"flex items-start justify-between gap-4",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl font-semibold","data-testid":"text-standalone-title",children:f.title}),e.jsxs("div",{className:"flex items-center gap-2 mt-1 text-sm text-muted-foreground",children:[f.tradeType&&e.jsx(H,{variant:"outline",children:f.tradeType}),f.clientName&&e.jsx("span",{children:f.clientName}),f.locationAddress&&e.jsxs("span",{children:["· ",f.locationAddress]})]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(j,{asChild:m.length>0,variant:"default",disabled:m.length===0,title:m.length===0?"Upload a plan sheet first to open the workspace":void 0,"data-testid":"button-open-workspace",children:m.length>0?e.jsxs(M,{href:`/takeoff/standalone/${f.id}/workspace`,children:[e.jsx(ie,{className:"w-4 h-4 mr-2"})," Open workspace"]}):e.jsxs("span",{children:[e.jsx(ie,{className:"w-4 h-4 mr-2"})," Open workspace"]})}),e.jsx(Ae,{standaloneTakeoffId:f.id,sheetIds:m.map(t=>t.id)}),e.jsxs(le,{open:N,onOpenChange:c,children:[e.jsx(oe,{asChild:!0,children:e.jsxs(j,{variant:"outline","data-testid":"button-tag-takeoff",children:[e.jsx(Ee,{className:"w-4 h-4 mr-2"})," Tag to bid/project"]})}),e.jsx(Oe,{onSubmit:t=>O.mutate(t),isSubmitting:O.isPending})]})]})]}),ee.length>0&&e.jsxs(_,{"data-testid":"standalone-tags-card",children:[e.jsx(G,{children:e.jsx(Z,{className:"text-sm font-semibold uppercase tracking-wide text-muted-foreground",children:"Tagged to"})}),e.jsx(W,{className:"space-y-2",children:ee.map(t=>{const s=t.bidId?je.find(d=>d.id===t.bidId):null,n=t.projectId?ge.find(d=>d.id===t.projectId):null,r=s?`${s.code??"Bid"} â ${s.name??s.id}`:n?`${n.code??"Project"} â ${n.name??n.id}`:t.bidId?`Bid ${t.bidId}`:`Project ${t.projectId}`,a=s!=null&&s.code?`/takeoff/${s.code}`:n!=null&&n.code?`/takeoff/project/${n.code}`:null;return e.jsxs("div",{className:"flex items-center justify-between gap-2 text-sm","data-testid":`tag-row-${t.id}`,children:[e.jsx("span",{className:"truncate",children:r}),e.jsxs("div",{className:"flex items-center gap-1 shrink-0",children:[a&&e.jsx(M,{href:a,"data-testid":`link-open-workspace-${t.id}`,children:e.jsxs(j,{size:"sm",variant:"outline",children:[e.jsx(ne,{className:"w-3.5 h-3.5 mr-1.5"})," Open in workspace"]})}),e.jsx(j,{size:"sm",variant:"ghost",onClick:()=>l.mutate(t.id),"data-testid":`button-untag-${t.id}`,children:e.jsx(Te,{className:"w-3.5 h-3.5"})})]})]},t.id)})})]}),e.jsxs(_,{children:[e.jsxs(G,{className:"flex flex-row items-center justify-between gap-3 flex-wrap",children:[e.jsxs(Z,{className:"text-sm font-semibold uppercase tracking-wide text-muted-foreground",children:["Sheets (",m.length,")"]}),e.jsxs("div",{className:"flex items-center gap-2",children:[m.length>0&&e.jsxs(D,{value:o,onValueChange:k,children:[e.jsx(U,{className:"h-8 w-[180px] text-xs","data-testid":"select-discipline-filter",children:e.jsx(P,{placeholder:"Filter by discipline"})}),e.jsxs(F,{children:[e.jsx(S,{value:"ALL",children:"All disciplines"}),e.jsx(S,{value:"UNCLASSIFIED",children:"Unclassified"}),Ne.map(t=>e.jsxs(S,{value:t,children:[t," â ",q[t]??t," (",Q.get(t)??0,")"]},t))]})]}),e.jsx(Fe,{maxNumberOfFiles:10,allowedFileTypes:[".pdf",".png",".jpg",".jpeg"],fileType:"DOCUMENT",onComplete:ve,testId:"button-upload-plan",children:e.jsxs(j,{size:"sm",variant:"outline",disabled:te,"data-testid":"button-add-sheet",children:[te?e.jsx(K,{className:"w-3.5 h-3.5 mr-1.5 animate-spin"}):e.jsx(De,{className:"w-3.5 h-3.5 mr-1.5"}),"Upload plan"]})})]})]}),e.jsx(W,{children:m.length===0?e.jsx("p",{className:"text-sm text-muted-foreground","data-testid":"text-sheets-empty",children:'No sheets yet. Upload a PDF or image plan above, then click "Open workspace" to start drawing measurements.'}):Y.length===0?e.jsx("p",{className:"text-sm text-muted-foreground","data-testid":"text-sheets-filtered-empty",children:"No sheets match this discipline filter."}):e.jsx("div",{className:"space-y-4",children:Y.map(t=>e.jsxs("div",{className:"space-y-1","data-testid":`sheet-group-${t.code}`,children:[e.jsxs("div",{className:"flex items-center gap-2 px-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground",children:[e.jsx("span",{children:t.code==="UNCLASSIFIED"?"Unclassified":`${t.code} â ${q[t.code]??t.code}`}),e.jsx(H,{variant:"secondary",className:"text-[10px] h-4 px-1.5",children:t.sheets.length})]}),t.sheets.map(s=>{const n=m.findIndex(r=>
1r.id===s.id);return e.jsxs("div",{className:"flex items-center gap-2 text-sm rounded px-2 py-1.5 hover:bg-muted","data-testid":`sheet-row-${s.id}`,children:[e.jsxs("div",{className:"flex items-center gap-0.5 shrink-0",children:[e.jsx(j,{type:"button",size:"icon",variant:"ghost",className:"h-6 w-6",disabled:n<=0||$.isPending,onClick:()=>A(s.id,"up"),title:"Move up","data-testid":`button-move-sheet-up-${s.id}`,children:e.jsx(Ue,{className:"w-3.5 h-3.5"})}),e.jsx(j,{type:"button",size:"icon",variant:"ghost",className:"h-6 w-6",disabled:n===m.length-1||$.isPending,onClick:()=>A(s.id,"down"),title:"Move down","data-testid":`button-move-sheet-down-${s.id}`,children:e.jsx(Pe,{className:"w-3.5 h-3.5"})})]}),e.jsxs(M,{href:`/takeoff/standalone/${f.id}/workspace?sheet=${s.id}`,className:"flex items-center gap-2 flex-1 min-w-0 cursor-pointer","data-testid":`sheet-link-${s.id}`,children:[e.jsx(de,{className:"w-4 h-4 text-muted-foreground shrink-0"}),e.jsx("span",{className:"flex-1 truncate",children:s.sheetName}),s.discipline&&e.jsx(H,{variant:s.disciplineSource==="USER"?"default":"outline",className:"text-[10px] h-5 px-1.5 shrink-0",title:s.disciplineSource==="USER"?"Set manually":s.disciplineSource==="AI_DETECTED"?`AI-detected (${s.disciplineConfidence??"n/a"})`:`Filename heuristic (${s.disciplineConfidence??"n/a"})`,"data-testid":`badge-discipline-${s.id}`,children:s.discipline}),e.jsx(ne,{className:"w-3.5 h-3.5 text-muted-foreground shrink-0"})]}),e.jsxs(D,{value:s.discipline??"NONE",onValueChange:r=>E.mutate({sheetId:s.id,discipline:r==="NONE"?null:r}),children:[e.jsx(U,{className:"h-7 w-[110px] text-xs","data-testid":`select-discipline-${s.id}`,children:e.jsx(P,{placeholder:"Set"})}),e.jsxs(F,{children:[e.jsx(S,{value:"NONE",children:"â Clear â"}),J.map(r=>e.jsxs(S,{value:r,children:[r," â ",q[r]]},r))]})]})]},s.id)})]},t.code))})})]}),e.jsxs(_,{children:[e.jsx(G,{children:e.jsxs(Z,{className:"text-sm font-semibold uppercase tracking-wide text-muted-foreground",children:["Files (",R.length,")"]})}),e.jsx(W,{children:R.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"No files attached."}):e.jsx("div",{className:"space-y-1",children:R.map(t=>e.jsxs("div",{className:"flex items-center gap-2 text-sm","data-testid":`file-row-${t.id}`,children:[e.jsx(de,{className:"w-4 h-4 text-muted-foreground"}),e.jsx("a",{href:t.fileUrl,target:"_blank",rel:"noreferrer",className:"hover:underline",children:t.fileName})]},t.id))})})]})]})}function Oe({onSubmit:v,isSubmitting:i}){const{data:u=[]}=fe(),{data:N=[]}=xe(),[c,o]=g.useState("bid"),[k,y]=g.useState("");return e.jsxs(ce,{"data-testid":"dialog-tag-takeoff",children:[e.jsxs(me,{children:[e.jsx(ue,{children:"Tag this takeoff"}),e.jsx(he,{children:"Linking attaches the takeoff to a bid or project. It will appear in their Suggested takeoffs and can be sent to their estimate."})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{children:[e.jsx(I,{children:"Destination type"}),e.jsxs(D,{value:c,onValueChange:h=>{o(h==="project"?"project":"bid"),y("")},children:[e.jsx(U,{"data-testid":"select-dest-kind",children:e.jsx(P,{})}),e.jsxs(F,{children:[e.jsx(S,{value:"bid",children:"Bid"}),e.jsx(S,{value:"project",children:"Project"})]})]})]}),e.jsxs("div",{children:[e.jsx(I,{children:c==="bid"?"Bid":"Project"}),e.jsxs(D,{value:k,onValueChange:y,children:[e.jsx(U,{"data-testid":"select-dest-id",children:e.jsx(P,{placeholder:"Select..."})}),e.jsx(F,{children:(c==="bid"?u:N).map(h=>{const w=h;return e.jsx(S,{value:w.id,children:w.name||w.code||w.id},w.id)})})]})]})]}),e.jsx(pe,{children:e.jsx(j,{onClick:()=>v(c==="bid"?{bidId:k}:{projectId:k}),disabled:!k||i,"data-testid":"button-confirm-tag",children:i?e.jsx(K,{className:"w-4 h-4 animate-spin"}):"Tag"})})]})}function Ae({standaloneTakeoffId:v,sheetIds:i}){const N=be({queries:i.map(c=>({queryKey:["/api/takeoff/sheets",c,"measurements"],queryFn:async()=>{const o=await fetch(`/api/takeoff/sheets/${c}/measurements`,{credentials:"include"});return o.ok?await o.json():[]}}))}).flatMap(c=>(c.data||[]).map(o=>o.id));return N.length===0?null:e.jsx(Le,{sourceTakeoffId:v,measurementIds:N,triggerLabel:"Send to Estimate"})}export{_e 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.