1import{r as c,j as e}from"./vendor-react-DKbe1Umz.js";import{a as z,u as J,r as C,B as x,l as h,I as G,C as I,v as B,D as W,c as X,d as Y,e as Z,f as ee,T as te,n as ae,q as M,o as O}from"./index-DZ74KeH3.js";import{u as se,a as V}from"./vendor-data-CjSe2wkl.js";import{T as ie,a as re,b as U,c as d,d as ne,e as o}from"./table-CAeITjOT.js";import{c1 as le,a$ as E,J as H,c0 as ce,i as de,E as oe,dF as ue,dE as me,cK as xe}from"./vendor-ui-DMaW9-Ov.js";import{a as he}from"./vendor-dates-5UNeOyFW.js";import"./vendor-charts-DWX9qznF.js";import"./vendor-forms-C2vWC2ab.js";function fe(r){switch(r.type){case"AREA":case"PITCHED_AREA":case"SURFACE_AREA":return{value:r.computedAreaFt2??0,unit:"sf"};case"LINEAR":case"LINEAR_WITH_DROP":case"PITCHED_LINEAR":return{value:r.computedLengthFt??0,unit:"lf"};case"VOLUME":return{value:r.computedVolumeCy??0,unit:"cy"};case"COUNT":return{value:r.count??0,unit:"ea"};default:return{value:0,unit:""}}}function T(r){if(!r)return null;try{const a=JSON.parse(r),i=a==null?void 0:a.sheetAttachment;if(i==="matched"||i==="fallback")return i}catch{}return null}function pe(r){if(!r)return null;try{const a=JSON.parse(r),i=(a==null?void 0:a.snapHitRatio)??(a==null?void 0:a.snap_hit_ratio)??(a==null?void 0:a.snapRatio);if(typeof i=="number"&&Number.isFinite(i))return i}catch{}return null}function qe(){const[r]=z(),{toast:a}=J(),i=c.useMemo(()=>{const t=r.indexOf("?");
1return t<0?null:new URLSearchParams(r.slice(t+1)).get("bid")},[r]),[v,K]=c.useState(""),[b,D]=c.useState("dollarValue"),[N,q]=c.useState("desc"),[g,Q]=c.useState(!1),[f,y]=c.useState(null),[F,w]=c.useState(""),_=c.useMemo(()=>i?["/api/takeoff/review-queue",{bidCode:i}]:["/api/takeoff/review-queue"],[i]),{data:k,isLoading:R,error:S}=se({queryKey:_,queryFn:async()=>{const t=i?`/api/takeoff/review-queue?bidCode=${encodeURIComponent(i)}`:"/api/takeoff/review-queue",l=await fetch(t,{credentials:"include"});if(!l.ok)throw new Error(`Failed to load queue: ${l.status}`);return l.json()}}),L=V({mutationFn:async t=>(await O("POST",`/api/takeoff/measurements/${t}/approve-review`,{})).json(),onSuccess:()=>{M.invalidateQueries({queryKey:["/api/takeoff/review-queue"]}),a({title:"Approved"})},onError:t=>a({title:"Approve failed",description:t.message,variant:"destructive"})}),$=V({mutationFn:async({id:t,note:l})=>(await O("POST",`/api/takeoff/measurements/${t}/reject-review`,{note:l})).json(),onSuccess:()=>{M.invalidateQueries({queryKey:["/api/takeoff/review-queue"]}),y(null),w(""),a({title:"Rejected â requester notified"})},onError:t=>a({title:"Reject failed",description:t.message,variant:"destructive"})}),P=c.useMemo(()=>(k??[]).filter(t=>T(t.metadata)==="fallback").length,[k]),A=c.useMemo(()=>{let t=k??[];if(g&&(t=t.filter(s=>T(s.metadata)==="fallback")),v.trim()){const s=v.toLowerCase();t=t.filter(n=>(n.label||"").toLowerCase().includes(s)||(n.bidCode||"").toLowerCase().includes(s)||(n.bidName||"").toLowerCase().includes(s)||(n.requestedByName||"").toLowerCase().includes(s))}return[...t].sort((s,n)=>{let u=0,m=0;switch(b){case"dollarValue":u=s.dollarValue??0,m=n.dollarValue??0;break;case"label":u=s.label??"",m=n.label??"";break;case"bidCode":u=s.bidCode??"",m=n.bidCode??"";break;case"type":u=s.type??"",m=n.type??"";break;case"requestedByName":u=s.requestedByName??"",m=n.requestedByName??"";break;case"reviewRequestedAt":u=s.reviewRequestedAt?new Date(s.reviewRequestedAt).getTime():0,m=n.reviewRequestedAt?new Date(n.reviewRequestedAt).getTime():0;break}return u<m?N==="asc"?-1:1:u>m?N==="asc"?1:-1:0})},[k,v,b,N,g]);c.useEffect(()=>{D("dollarValue"),q("desc")},[i]);const p=t=>{b===t?q(l=>l==="asc"?"desc":"asc"):(D(t),q(t==="dollarValue"||t==="reviewRequestedAt"?"desc":"asc"))},j=({k:t})=>b!==t?null:N==="asc"?e.jsx(me,{className:"inline w-3 h-3 ml-1"}):e.jsx(xe,{className:"inline w-3 h-3 ml-1"});return e.jsxs("div",{className:"min-h-screen bg-background",children:[e.jsxs("main",{className:"mx-auto max-w-7xl px-4 py-6 sm:px-6 sm:py-8",children:[e.jsx("div",{className:"mb-4",children:e.jsx(C,{href:"/takeoff",children:e.jsxs(x,{variant:"ghost",size:"sm","data-testid":"button-back-to-takeoff",children:[e.jsx(le,{className:"w-4 h-4 mr-1"})," Back to Takeoff"]})})}),e.jsxs("div",{className:"mb-6",children:[e.jsxs("h1",{className:"text-2xl font-semibold flex items-center gap-2",children:[e.jsx(E,{className:"w-6 h-6 text-primary"}),"Takeoff Review Queue"]}),e.jsxs("p",{className:"text-sm text-muted-foreground mt-1",children:["Senior estimators approve or reject high-value measurements before bids ship.",i&&e.jsxs(e.Fragment,{children:[" ","Filtered to bid ",e.jsx(h,{variant:"outline",className:"font-mono ml-1",children:i})," ",e.jsx(C,{href:"/takeoff/review-queue",children:e.jsx(x,{variant:"ghost",size:"sm",className:"px-1 h-auto underline","data-testid":"button-clear-bid-filter",children:"Show all"})})]})]})]}),e.jsxs("div",{className:"mb-4 flex flex-col sm:flex-row gap-2",children:[e.jsx(G,{value:v,onChange:t=>K(t.target.value),placeholder:"Search by measurement label, bid code, requesterâ¦","data-testid":"input-review-queue-search"}),e.jsxs(x,{variant:g?"default":"outline",onClick:()=>Q(t=>!t),disabled:P===0&&!g,"data-testid":"button-toggle-fallback-only",className:"whitespace-nowrap",children:[e.jsx(H,{className:"w-4 h-4 mr-1.5"}),"Fallback sheet only",e.jsx(h,{variant:"secondary",className:"ml-2 tabular-nums","data-testid":"badge-fallback-total",children:P})]})]}),R&&e.jsxs("div",{className:"flex items-center gap-2 text-muted-foreground py-12 justify-center","data-testid":"text-review-queue-loading",children:[e.jsx(ce,{className:"w-4 h-4 animate-spin"})," Loading queueâ¦"]}),S&&e.jsxs("div",{className:"flex items-center gap-2 text-destructive py-12 justify-center",children:[e.jsx(de,{className:"w-4 h-4"})," Failed to load review queue."]}),!R&&!S&&A.length===0&&e.jsx(I,{"data-testid":"card-review-queue-empty",children:e.jsxs(B,{className:"py-12 text-center text-muted-foreground",children:[e.jsx(E,{className:"w-10 h-10 mx-auto mb-2 opacity-50"}),"No measurements awaiting review."]})}),!R&&!S&&A.length>0&&e.jsx(I,{children:e.jsx(B,{className:"p-0 overflow-x-auto",children:e.jsxs(ie,{"data-testid":"table-review-queue",children:[e.jsx(re,{children:e.jsxs(U,{children:[e.jsxs(d,{className:"cursor-pointer select-none",onClick:()=>p("label"),"data-testid":"th-sort-label",children:["Measurement",e.jsx(j,{k:"label"})]}),e.jsxs(d,{className:"cursor-pointer select-none",onClick:()=>p("bidCode"),"data-testid":"th-sort-bid",children:["Bid / Sheet",e.jsx(j,{k:"bidCode"})]}),e.jsxs(d,{className:"cursor-pointer select-none",onClick:()=>p("type"),"data-testid":"th-sort-type",children:["Type",e.jsx(j,{k:"type"})]}),e.jsx(d,{className:"text-right",children:"Quantity"}),e.jsx(d,{children:"Captured by"}),e.jsx(d,{children:"Scale"}),e.jsx(d,{className:"text-right",children:"Snap hit"}),e.jsxs(d,{className:"cursor-pointer select-none",onClick:()=>p("requestedByName"),"data-testid":"th-sort-requester",children:["Requested by",e.jsx(j,{k:"requestedByName"})]}),e.jsxs(d,{className:"cursor-pointer select-none",onClick:()=>p("reviewRequestedAt"),"data-testid":"th-sort-requested-at",children:["Requested",e.jsx(j,{k:"reviewRequestedAt"})]}),e.jsxs(d,{className:"text-right cursor-pointer select-none",onClick:()=>p("dollarValue"),"data-testid":"th-sort-dollar",children:["Dollar",e.jsx(j,{k:"dollarValue"})]}),e.jsx(d,{className:"text-right",children:"Actions"})]})}),e.jsx(ne,{children:A.map(t=>{const l=fe(t),s=pe(t.metadata),n=T(t.metadata);return e.jsxs(U,{"data-testid":`row-review-${t.id}`,children:[e.jsxs(o,{className:"max-w-[260px]",children:[e.jsx("div",{className:"font-medium truncate","data-testid":`text-review-label-${t.id}`,children:t.label||"Unlabelled measurement"}),t.reviewNote&&e.jsxs("div",{className:"text-xs text-muted-foreground italic truncate",children:["â",t.reviewNote,"â"]}),e.jsx(h,{variant:t.reviewStatus==="REJECTED"?"destructive":"secondary",className:"text-[10px] mt-1","data-testid":`badge-review-status-${t.id}`,children:t.reviewStatus??"PENDING"})]}),e.jsxs(o,{className:"text-xs",children:[t.bidCode&&e.jsx(C,{href:`/bids/${t.bidCode}`,children:e.jsxs(h,{variant:"outline",className:"font-mono curs
1or-pointer",children:[e.jsx(oe,{className:"w-3 h-3 mr-1"}),t.bidCode]})}),t.sheetName&&e.jsx("div",{className:"text-muted-foreground truncate max-w-[180px] mt-1",children:t.sheetName}),n==="fallback"&&e.jsxs(h,{variant:"destructive",className:"text-[10px] mt-1 inline-flex items-center gap-1",title:"AI map-reduce could not match a sheet citation; this measurement was attached to the lowest-index sheet. Verify before approving.","data-testid":`badge-fallback-sheet-${t.id}`,children:[e.jsx(H,{className:"w-3 h-3"}),"Fallback sheet"]})]}),e.jsx(o,{children:e.jsx(h,{variant:"secondary",className:"text-xs",children:t.type})}),e.jsxs(o,{className:"text-right tabular-nums",children:[l.value.toLocaleString("en-US",{maximumFractionDigits:1}),e.jsx("span",{className:"text-muted-foreground text-xs ml-1",children:l.unit})]}),e.jsx(o,{className:"text-xs",children:e.jsx(h,{variant:"outline",className:"text-[10px]",children:t.source??"USER"})}),e.jsx(o,{className:"text-xs text-muted-foreground",children:t.sheetScaleLabel||(t.sheetScalePxPerFoot?`${t.sheetScalePxPerFoot.toFixed(2)} px/ft`:"â")}),e.jsx(o,{className:"text-right text-xs tabular-nums",children:s!==null?`${Math.round(s*100)}%`:"â"}),e.jsx(o,{className:"text-xs truncate max-w-[140px]",children:t.requestedByName??"â"}),e.jsx(o,{className:"text-xs text-muted-foreground whitespace-nowrap",children:t.reviewRequestedAt?he(new Date(t.reviewRequestedAt),"MMM d, h:mm a"):"â"}),e.jsxs(o,{className:"text-right font-semibold tabular-nums","data-testid":`text-review-dollar-${t.id}`,children:["$",(t.dollarValue??0).toLocaleString("en-US",{maximumFractionDigits:0})]}),e.jsx(o,{className:"text-right",children:e.jsxs("div",{className:"flex gap-1 justify-end flex-wrap",children:[e.jsx(x,{size:"sm",variant:"default",onClick:()=>L.mutate(t.id),disabled:L.isPending||t.reviewStatus!=="PENDING","data-testid":`button-approve-${t.id}`,children:e.jsx(E,{className:"w-3.5 h-3.5"})}),e.jsx(x,{size:"sm",variant:"destructive",onClick:()=>{y(t),w("")},disabled:t.reviewStatus!=="PENDING","data-testid":`button-reject-${t.id}`,children:e.jsx(ue,{className:"w-3.5 h-3.5"})}),t.bidCode&&e.jsx(C,{href:`/takeoff/${t.bidCode}`,children:e.jsx(x,{size:"sm",variant:"outline","data-testid":`button-open-takeoff-${t.id}`,children:"Open"})})]})})]},t.id)})})]})})})]}),e.jsx(W,{open:!!f,onOpenChange:t=>!t&&y(null),children:e.jsxs(X,{children:[e.jsxs(Y,{children:[e.jsx(Z,{children:"Reject measurement"}),e.jsxs(ee,{children:[(f==null?void 0:f.label)||"This measurement"," will stay in the queue with status REJECTED so the requester can fix it. The note below is included in their notification."]})]}),e.jsx(te,{value:F,onChange:t=>w(t.target.value),placeholder:"Reason for rejectionâ¦",rows:4,maxLength:2e3,"data-testid":"textarea-reject-note"}),e.jsxs(ae,{children:[e.jsx(x,{variant:"ghost",onClick:()=>y(null),"data-testid":"button-cancel-reject",children:"Cancel"}),e.jsx(x,{variant:"destructive",onClick:()=>f&&$.mutate({id:f.id,note:F}),disabled:$.isPending,"data-testid":"button-confirm-reject",children:"Reject & notify"})]})]})})]})}export{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.