PageSourceSearch

https://fieldserviceiq.ai/assets/ProjectApprovals-0XyqLHY-.js

js fieldserviceiq.ai collected 2026-10-05 13:10:24 UTC 25,302 bytes, 6 lines download raw bytes

1import{d as ce,u as re,j as e}from"./vendor-data-_Pz25YLs.js";import{r as q,L as me}from"./vendor-react-C5ET9VRQ.js";import{c as pe,D as ue,f as xe,g as be,h as fe,ab as he,J as S,B as N,P as Y,z as ge,L as ee,n as te,I as H,U as je,q as _e,s as p,ah as F,aj as ve,c9 as ye,e as Ne,al as we,ay as ke}from"./index-C15KveKt.js";import{C as R,c as M,a as Ce,b as Ae}from"./card-DKtZ9FmL.js";import{A as De}from"./ApprovalStatusBadge-CcQZUca_.js";import{n as Se,g as $e}from"./approvalPacketValidation-Vk45mPi_.js";import{S as Fe}from"./switch-BpXxs5tu.js";import{S as ae}from"./send-CNlcoSAp.js";import{C as qe}from"./copy-Cmf0v503.js";import{T as ie}from"./trash-2-CeDNviAG.js";import{C as Te}from"./calendar-days-CQ9NU205.js";import{M as Ie}from"./mail-Eg027Dpq.js";import{f as ne}from"./format-Bo4AVCK2.js";import{a as Ke}from"./addDays-Caep41KN.js";import{useProject as Re}from"./ProjectLayout-BcoKX1mp.js";import"./clock-ByM7PWKN.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 Me=pe("File",[["path",{d:"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z",key:"1rqfz7"}],["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}]]);async function de(g,w,b){try{const[{data:u},{data:_}]=await Promise.all([p.from("jobs").select("title").eq("id",g).maybeSingle(),p.from("project_documents").select("document_number, title").eq("id",w).maybeSingle()]);if(!_)return;await ve({jobId:g,jobTitle:(u==null?void 0:u.title)||"Job",documentNumber:_.document_number,documentTitle:_.title,excludeUserId:b??null})}catch(u){console.error("notifyJobDocumentLinked failed",u)}}const Pe=[{value:"drawing",label:"Drawing"},{value:"spec",label:"Spec Sheet"},{value:"bulletin",label:"Bulletin"},{value:"permit",label:"Permit"},{value:"photo",label:"Photo"},{value:"utility",label:"Utility"},{value:"supporting",label:"Supporting Document"},{value:"site_map",label:"Site Map"},{value:"inspection",label:"Inspection"},{value:"proposal",label:"Proposal"}],Je=["Landlord","Customer","Operator","Property Manager","Other"],le={rfi:"RFI",submittal:"Submittal",document:"Document",landlord_approval:"Landlord Approval",upload:"New Upload"},oe={rfi:"bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300",submittal:"bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-300",document:"bg-amber-100 text-amber-800 dark:bg-amber-900 dark:text-amber-300",landlord_approval:"bg-emerald-100 text-emerald-800 dark:bg-emerald-900 dark:text-emerald-300",upload:"bg-sky-100 text-sky-800 dark:bg-sky-900 dark:text-sky-300"};let Ee=0;function V(){return`entry-${++Ee}`}const X=ne(Ke(new Date,7),"yyyy-MM-dd");function Le({open:g,onOpenChange:w,projectId:b}){const u=ce(),[_,f]=q.useState([{id:V(),itemKey:"",recipients:[{name:"",email:"",role_label:"Landlord",is_required:!0}],dueAt:X,message:"",uploadDocType:"supporting",uploadJobId:""}]),[T,P]=q.useState(!1),[I,x]=q.useState(""),j=q.useRef({}),{data:v,isLoading:W}=re({queryKey:["batch_approval_items",b],queryFn:async()=>{const t=[],[n,a,s,i]=await Promise.all([p.from("project_rfis").select("id, subject, rfi_number, project_id, status").eq("project_id",b),p.from("project_submittals").select("id, spec_section, submittal_type, submittal_number, project_id, status").eq("project_id",b),p.from("project_documents").select("id, title, document_number, project_id").eq("project_id",b),p.from("jobs").select("id, title").eq("project_id",b)]),d=i.data||[],c=new Map(d.map(l=>[l.id,l.title]));for(const l of n.data||[])t.push({type:"rfi",id:l.id,entity_type:"project",entity_id:b,label:"RFI",number:`RFI-${String(l.rfi_number).padStart(3,"0")}`,title:l.subject||void 0});for(const l of a.data||[])t.push({type:"submittal",id:l.id,entity_type:"project",entity_id:b,label:"Submittal",number:`SUB-${String(l.submittal_number).padStart(3,"0")}`,title:`${l.spec_section} - ${l.submittal_type}`});for(const l of s.data||[])t.push({type:"document",id:l.id,entity_type:"project",entity_id:b,label:"Document",number:l.document_number,title:l.title||void 0});
6const h=d.map(l=>l.id);if(h.length>0){const{data:l}=await p.from("job_landlord_approvals").select("id, job_id, landlord_name, landlord_company").in("job_id",h);for(const o of l||[])t.push({type:"landlord_approval",id:o.id,entity_type:"job",entity_id:o.job_id,label:"Landlord Approval",number:o.landlord_company||o.landlord_name||"Landlord",jobId:o.job_id,jobTitle:c.get(o.job_id)||"Unknown Job"})}return{items:t,jobs:d}},enabled:g}),k=(v==null?void 0:v.items)||[],J=(v==null?void 0:v.jobs)||[],E=q.useMemo(()=>I?k.filter(t=>t.jobId?t.jobId===I:!0):k,[k,I]),L=()=>{f(t=>[...t,{id:V(),itemKey:"",recipients:[{name:"",email:"",role_label:"Landlord",is_required:!0}],dueAt:X,message:"",uploadDocType:"supporting",uploadJobId:""}])},U=t=>{f(n=>n.filter(a=>a.id!==t))},O=t=>{f(n=>{const a=n.find(c=>c.id===t);if(!a)return n;const s=n.indexOf(a),i={id:V(),itemKey:"",recipients:a.recipients.map(c=>({...c})),dueAt:a.dueAt,message:a.message,uploadDocType:a.uploadDocType,uploadJobId:a.uploadJobId},d=[...n];return d.splice(s+1,0,i),d})},z=(t,n)=>{f(a=>a.map(s=>s.id===t?{...s,itemKey:n,uploadedFile:void 0}:s))},C=async(t,n,a)=>{if(f(s=>s.map(i=>i.id===t?{...i,[n]:a}:i)),n==="uploadDocType"){const s=_.find(i=>i.id===t);if(s!=null&&s.itemKey&&s.itemKey.startsWith("document:")&&s.uploadedFile){const i=s.itemKey.split(":")[1],d=a==="drawing"?"drawing":a==="spec"?"spec":"supporting";await p.from("project_documents").update({document_type:a,category:d}).eq("id",i)}}if(n==="uploadJobId"){const s=_.find(i=>i.id===t);if(s!=null&&s.itemKey&&s.itemKey.startsWith("document:")&&s.uploadedFile){const i=s.itemKey.split(":")[1];if(s.uploadJobId&&await p.from("job_documents").delete().eq("document_id",i).eq("job_id",s.uploadJobId),a){await p.from("job_documents").insert({document_id:i,job_id:a});const{data:{user:d}}=await p.auth.getUser();await de(a,i,(d==null?void 0:d.id)??null)}}}},G=async(t,n)=>{var i,d;let a="supporting",s="";f(c=>{const h=c.find(l=>l.id===t);return h&&(a=h.uploadDocType||"supporting",s=h.uploadJobId||""),c.map(l=>l.id===t?{...l,itemKey:"upload:pending",uploadedFile:{file:n,uploading:!0,name:n.name}}:l)});try{const c=`${b}/${Date.now()}-${n.name}`,{error:h}=await p.storage.from("project-documents").upload(c,n);if(h)throw h;const{data:l}=await p.from("project_documents").select("document_number").eq("project_id",b).order("created_at",{ascending:!1}).limit(1);let o="DOC-001";if(l&&l.length>0&&l[0].document_number){const B=l[0].document_number.match(/(\d+)$/);B&&(o=`DOC-${String(parseInt(B[1])+1).padStart(3,"0")}`)}const K=a,{data:D,error:y}=await p.from("project_documents").insert({project_id:b,title:n.name,document_number:o,file_url:c,document_type:K,discipline:"General",category:K==="drawing"?"drawing":K==="spec"?"spec":"supporting"}).select().single();if(y)throw y;const{data:se}=await p.auth.getUser();await p.from("document_revisions").insert({document_id:D.id,file_url:c,file_mime_type:n.type||"application/octet-stream",revision_number:1,title:n.name,uploaded_by_user_id:((i=se.user)==null?void 0:i.id)||null,uploaded_by_type:"portal_user",source:"internal_upload",kind:"revision"}),s&&(await p.from("job_documents").insert({document_id:D.id,job_id:s}),await de(s,D.id,((d=se.user)==null?void 0:d.id)??null)),f(B=>B.map(Q=>Q.id===t?{...Q,itemKey:`document:${D.id}`,uploadedFile:{...Q.uploadedFile,uploading:!1,url:c}}:Q)),F.success(`Uploaded ${n.name}`)}catch(c){F.error(`Upload failed: ${c.message}`),f(h=>h.map(l=>l.id===t?{...l,itemKey:"",uploadedFile:void 0}:l))}},$=t=>{f(n=>n.map(a=>a.id===t?{...a,recipients:[...a.recipients,{name:"",email:"",role_label:"Customer",is_required:!0}]}:a))},Z=(t,n)=>{f(a=>a.map(s=>s.id===t?{...s,recipients:s.recipients.filter((i,d)=>d!==n)}:s))},A=(t,n,a,s)=>{f(i=>i.map(d=>d.id===t?{...d,recipients:d.recipients.map((c,h)=>h===n?{...c,[a]:s}:c)}:d))},m=async()=>{const t=_.filter(a=>{var i;return!a.itemKey||a.itemKey==="upload:pending"||(i=a.uploadedFile)!=null&&i.uploading?!1:a.recipients.filter(d=>d.name.trim()&&d.email.trim()).length>0});if(t.length===0){F.error("Add at least one approval with an item and approver");return}const n=/^[^\s@]+@[^\s@]+\.[^\s@]+$/;for(const a of t)for(const s of a.recipients)if(s.email.trim()&&!n.test(s.email)){F.error(`Invalid email: ${s.email}`);return}P(!0);try{const a=t.map(c=>{const[h,l]=c.itemKey.split(":"),o=k.find(y=>y.type===h&&y.id===l),K=Se({entity_type:(o==null?void 0:o.entity_type)||"project",entity_id:(o==null?void 0:o.entity_id)||b,document_id:(o==null?void 0:o.type)==="document"?o.id:void 0,rfi_id:(o==null?void 0:o.type)==="rfi"?o.id:void 0,submittal_id:(o==null?void 0:o.type)==="submittal"?o.id:void 0,landlord_a
6pproval_id:(o==null?void 0:o.type)==="landlord_approval"?o.id:void 0,due_at:c.dueAt?new Date(c.dueAt).toISOString():void 0,message_to_approvers:c.message||void 0}),D=$e(K);if(D)throw new Error(D);return o?{type:o.type,id:o.id,entity_type:o.entity_type,entity_id:o.entity_id,recipients:c.recipients.filter(y=>y.name.trim()&&y.email.trim()),due_at:c.dueAt?new Date(c.dueAt).toISOString():void 0,message_to_approvers:c.message||void 0}:{type:h,id:l,entity_type:"project",entity_id:b,recipients:c.recipients.filter(y=>y.name.trim()&&y.email.trim()),due_at:c.dueAt?new Date(c.dueAt).toISOString():void 0,message_to_approvers:c.message||void 0}}),{data:s}=await p.auth.getSession();if(!s.session)throw new Error("Not authenticated");const i=await fetch("https://nblhnpkxepwbpmhghpmk.supabase.co/functions/v1/batch-approvals",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s.session.access_token}`},body:JSON.stringify({items:a})});if(!i.ok){const c=await i.json();throw new Error(c.error||"Failed to create approvals")}const d=await i.json();F.success(`Created ${d.packets_created} approval(s), sent ${d.emails_sent} notification email(s)`),u.invalidateQueries({queryKey:["project_all_approvals"]}
6),u.invalidateQueries({queryKey:["approval-packets"]}),f([{id:V(),itemKey:"",recipients:[{name:"",email:"",role_label:"Landlord",is_required:!0}],dueAt:X,message:"",uploadDocType:"supporting",uploadJobId:""}]),w(!1)}catch(a){F.error(a.message||"Failed to send approvals")}finally{P(!1)}},r=_.filter(t=>t.itemKey&&t.itemKey!=="upload:pending"&&t.recipients.some(n=>n.email.trim())).length;return e.jsx(ue,{open:g,onOpenChange:w,children:e.jsxs(xe,{className:"max-w-4xl h-[90vh] flex flex-col overflow-hidden min-w-0 p-0 gap-0",children:[e.jsxs(be,{className:"shrink-0 px-6 pt-6 pb-4 border-b",children:[e.jsxs(fe,{className:"flex items-center gap-2",children:[e.jsx(ae,{className:"h-5 w-5"}),"Batch Create Approvals"]}),e.jsx(he,{children:"Add approval combinations — each item gets its own approvers, due date, and message. One consolidated email per unique recipient."})]}),e.jsx("div",{className:"flex-1 min-h-0 overflow-y-auto px-6 py-4",children:e.jsx("div",{className:"space-y-6",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(S,{className:"text-base font-medium",children:"Approval Items"}),e.jsxs(N,{type:"button",variant:"outline",size:"sm",onClick:L,children:[e.jsx(Y,{className:"h-4 w-4 mr-1"}),"Add Item"]})]}),_.map((t,n)=>{var a;return e.jsxs("div",{className:"border rounded-lg p-4 space-y-3 bg-muted/20",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("span",{className:"text-sm font-medium text-muted-foreground",children:["Approval ",n+1]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(N,{type:"button",variant:"ghost",size:"sm",onClick:()=>O(t.id),title:"Duplicate with same approvers",className:"text-muted-foreground",children:e.jsx(qe,{className:"h-3.5 w-3.5"})}),_.length>1&&e.jsx(N,{type:"button",variant:"ghost",size:"sm",onClick:()=>U(t.id),className:"text-destructive",children:e.jsx(ie,{className:"h-3.5 w-3.5"})})]})]}),e.jsxs("div",{children:[e.jsx(S,{className:"text-xs mb-1 block",children:"Item"}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs("select",{value:t.uploadedFile?"":t.itemKey,onChange:s=>z(t.id,s.target.value),disabled:!!t.uploadedFile,className:"flex h-10 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:opacity-50",children:[e.jsx("option",{value:"",children:"Select an item..."}),E.map(s=>{const i=`${s.type}:${s.id}`;return e.jsxs("option",{value:i,children:["[",le[s.type],"] ",s.number,s.title?` — ${s.title}`:"",s.jobTitle?` (${s.jobTitle})`:""]},i)})]}),e.jsx("input",{type:"file",ref:s=>{j.current[t.id]=s},className:"hidden",accept:".pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt,.csv,.rtf,.zip,.dwg,.dxf,.rvt,.ifc,.skp,.png,.jpg,.jpeg,.gif,.webp,.svg,.heic",onChange:s=>{var d;const i=(d=s.target.files)==null?void 0:d[0];i&&G(t.id,i),s.target.value=""}}),e.jsxs(N,{type:"button",variant:"outline",size:"sm",className:"shrink-0 h-10",onClick:()=>{var s;return(s=j.current[t.id])==null?void 0:s.click()},disabled:(a=t.uploadedFile)==null?void 0:a.uploading,children:[e.jsx(ge,{className:"h-4 w-4 mr-1"}),"Upload"]})]}),t.uploadedFile&&!t.uploadedFile.uploading&&e.jsxs("div",{className:"mt-2 grid grid-cols-1 sm:grid-cols-2 gap-3",children:[e.jsxs("div",{children:[e.jsx(S,{className:"text-xs mb-1 block text-muted-foreground",children:"Document Type"}),e.jsx("select",{value:t.uploadDocType,onChange:s=>C(t.id,"uploadDocType",s.target.value),className:"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",children:Pe.map(s=>e.jsx("option",{value:s.value,children:s.label},s.value))})]}),e.jsxs("div",{children:[e.jsx(S,{className:"text-xs mb-1 block text-muted-foreground",children:"Associate with Job"}),e.jsxs("select",{value:t.uploadJobId,onChange:s=>C(t.id,"uploadJobId",s.target.value),className:"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",children:[e.jsx("option",{value:"",children:"No job (project-level only)"}),J.map(s=>e.jsx("option",{value:s.id,children:s.title},s.id))]})]})]}),t.uploadedFile&&e.jsx("div",{className:"mt-1.5 space-y-1.5",children:e.jsx("div",{className:"flex items-center gap-2 text-sm",children:t.uploadedFile.uploading?e.jsxs("span",{className:"flex items-center gap-1.5 text-muted-foreground",children:[e.jsx(ee,{className:"h-3.5 w-3.5 animate-spin"}),"Uploading ",t.uploadedFile.name,"..."]}):e.jsxs(e.Fragment,{children:[e.jsx("span",{className:`inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium ${oe.upload}`,children:"Uploaded"}),e.jsx(te,{className:"h-3.5 w-3.5 text-muted-foreground"}),e.jsx("span",{className:"text-muted-foreground truncate max-w-[200px]",children:t.uploadedFile.name}),e.jsx(N,{type:"button",variant:"ghost",size:"sm",className:"h-6 text-destructive text-xs px-1",onClick:()=>f(s=>s.map(i=>i.id===t.id?{...i,itemKey:"",uploadedFile:void 0}:i)),children:"Remove"})]})})}),!t.uploadedFile&&t.itemKey&&e.jsx("div",{className:"mt-1",children:(()=>{const[s]=t.itemKey.split(":");return e.jsx("span",{className:`inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium ${oe[s]||""}`,children:le[s]||s})})()})]}),e.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-2",children:[e.jsxs("div",{children:[e.jsxs(S,{className:"text-xs flex items-center gap-1 mb-1",children:[e.jsx(Te,{className:"h-3 w-3"}),"Due Date (optional)"]}),e.jsx(H,{type:"date",value:t.dueAt,onChange:s=>C(t.id,"dueAt",s.target.value),className:"h-9 text-sm"})]}),e.jsxs("div",{children:[e.jsx(S,{className:"text-xs mb-1 block",children:"Message to Approvers (optional)"}),e.jsx(H,{value:t.message,onChange:s=>C(t.id,"message",s.target.value),placeholder:"Please review and approve...",className:"h-9 text-sm"})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(S,{className:"text-xs",children:"Approvers"}),e.jsxs(N,{type:"button",variant:"ghost",size:"sm",onClick:()=>$(t.id),className:"h-7 text-xs",children:[e.jsx(Y,{className:"h-3 w-3 mr-1"}),"Add Approver"]})]}),t.recipients.map((s,i)=>e.jsxs("div",{className:"space-y-1.5 rounded-md border bg-background/50 p-2",children:[e.jsxs("div",{className:"flex items-start gap-1.5",children:[e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-3 gap-1.5 flex-1",children:[e.jsxs("div",{className:"relative",children:[e.jsx(je,{className:"absolute left-2 top-2.5 h-3.5 w-3.5 text-muted-foreground"}),e.jsx(H,{placeholder:"Name",value:s.name,onChange:d=>A(t.id,i,"name",d.target.value),className:"pl-7 h-9 text-sm"})]}),e.jsxs("div",{className:"relative",children:[e.jsx(Ie,{className:"absolute left-2 top-2.5 h-3.5 w-3.5 text-muted-foreground"}),e.jsx(H,{type:"email",placeholder:"Email",value:s.email,onChange:d=>A(t.id,i,"email",d.target.value),className:"pl-7 h-9 text-sm"})]}),e.jsxs("div",{className:"relative",children:[e.jsx(_e,{className:"absolute left-2 top-2.5 h-3.5 w-3.5 text-muted-foreground"}),e.jsx("select",{value:s.role_label,onChange:d=>A(t.id,i,"role_label",d.target.value),className:"flex h-9 w-full rounded-md border border-input bg-transparent pl-7 pr-2 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",children:Je.map(d=>e.jsx("option",{value:d,children:d},d))})]})]}),t.recipients.length>1&&e.jsx(N,{type:"button",variant:"ghost",size:"icon",onClick:()=>Z(t.id,i),className:"text-destructive shrink-0 h-9 w-9",children:e.jsx(ie,{className:"h-3.5 w-3.5"})})]}),e.jsxs("div",{className:"flex items-center justify-between px-1",children:[e.jsx("span",{className:"text-[11px] text-muted-foreground",children:s.is_required?"Approval required":"Notified only (not required to approve)"}),e.jsx(Fe,{checked:s.is_required,onCheckedChange:d=>A(t.id,i,"is_required",d)})]})]},i))]})]},t.id)})]})})}),e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-2 px-6 py-4 border-t shrink-0",children:[e.jsxs("p",{className:"text-xs text-muted-foreground",children:[r," approval",r!==1?"s":""," ready to send"]}),e.jsxs("div",{className:"flex gap-3",children:[e.jsx(N,{variant:"outline",onClick:()=>w(!1),disabled:T,children:"Cancel"}),e.jsx(N,{onClick:m,disabled:T||r===0,children:T?e.jsxs(e.Fragment,{children:[e.jsx(ee,{className:"h-4 w-4 mr-2 animate-spin"}),"Sending..."]}):e.jsxs(e.Fragment,{children:[e.jsx(ae,{className:"h-4 w-4 mr-2"}),"Send ",r," Approval",r!==1?"s":""]})})]})]})]})})}const Ue={rfi:{label:"RFI",icon:te,badgeClass:"bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300"},submittal:{label:"Submittal",icon:we,badgeClass:"bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-300"},document:{label:"Drawing & Spec",icon:Me,badgeClass:"bg-amber-100 text-amber-800 dark:bg-amber-900 dark:text-amber-300"}
6,landlord_approval:{label:"Landlord",icon:ke,badgeClass:"bg-emerald-100 text-emerald-800 dark:bg-emerald-900 dark:text-emerald-300"}};function dt(){const{project:g}=Re(),[w,b]=q.useState(!1),{data:u,isLoading:_}=re({queryKey:["project_all_approvals",g.id],queryFn:async()=>{const x=[],[j,v,W,k]=await Promise.all([p.from("project_rfis").select("id, subject, rfi_number").eq("project_id",g.id),p.from("project_submittals").select("id, spec_section, submittal_type, submittal_number").eq("project_id",g.id),p.from("project_documents").select("id, title, document_number").eq("project_id",g.id),p.from("jobs").select("id, title").eq("project_id",g.id)]),J=(j.data||[]).map(m=>m.id),E=new Map((j.data||[]).map(m=>[m.id,m])),L=(v.data||[]).map(m=>m.id),U=new Map((v.data||[]).map(m=>[m.id,m])),O=(W.data||[]).map(m=>m.id),z=new Map((W.data||[]).map(m=>[m.id,m])),C=(k.data||[]).map(m=>m.id),G=new Map((k.data||[]).map(m=>[m.id,m.title])),$=[];J.length>0&&$.push(Promise.resolve(p.from("approval_packets").select("id, status, created_at, rfi_id, submittal_id, document_id, type").in("rfi_id",J))),L.length>0&&$.push(Promise.resolve(p.from("approval_packets").select("id, status, created_at, rfi_id, submittal_id, document_id, type").in("submittal_id",L))),O.length>0&&$.push(Promise.resolve(p.from("approval_packets").select("id, status, created_at, rfi_id, submittal_id, document_id, type").in("document_id",O)));const Z=await Promise.all($),A=new Set;for(const m of Z)for(const r of m.data||[])if(!A.has(r.id)){if(A.add(r.id),r.rfi_id&&E.has(r.rfi_id)){const t=E.get(r.rfi_id);x.push({id:r.id,kind:"rfi",title:t.subject||`RFI #${t.rfi_number}`,subtitle:`RFI #${t.rfi_number}`,status:r.status,createdAt:r.created_at,linkTo:`/projects/${g.id}/files/rfis/${t.id}`})}else if(r.submittal_id&&U.has(r.submittal_id)){const t=U.get(r.submittal_id);x.push({id:r.id,kind:"submittal",title:`${t.submittal_type} — ${t.spec_section}`,subtitle:`Submittal #${t.submittal_number}`,status:r.status,createdAt:r.created_at,linkTo:`/projects/${g.id}/files/submittals/${t.id}`})}else if(r.document_id&&z.has(r.document_id)){const t=z.get(r.document_id);x.push({id:r.id,kind:"document",title:t.title||`Document #${t.document_number}`,subtitle:`Document #${t.document_number}`,status:r.status,createdAt:r.created_at,linkTo:`/projects/${g.id}/files/documents/${t.id}`})}}if(C.length>0){const{data:m}=await p.from("job_landlord_approvals").select("id, job_id, status, landlord_name, landlord_company, created_at").in("job_id",C).order("created_at",{ascending:!1});for(const r of m||[])x.push({id:r.id,kind:"landlord_approval",title:r.landlord_company||r.landlord_name||"Landlord Approval",subtitle:G.get(r.job_id)||"Unknown Job",status:r.status,createdAt:r.created_at,linkTo:`/jobs/${r.job_id}`})}return x.sort((m,r)=>new Date(r.createdAt).getTime()-new Date(m.createdAt).getTime()),x}}),f=(u==null?void 0:u.length)||0,T=(u==null?void 0:u.filter(x=>["pending","draft","sent","in_review"].includes(x.status)).length)||0,P=(u==null?void 0:u.filter(x=>["approved","approved_as_noted"].includes(x.status)).length)||0,I=(u==null?void 0:u.filter(x=>["rejected","revise_and_resubmit","revision_requested"].includes(x.status)).length)||0;return _?e.jsx("div",{className:"flex items-center justify-center h-64",children:e.jsx(ee,{className:"h-8 w-8 animate-spin text-muted-foreground"})}):e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("h2",{className:"text-lg font-semibold",children:"Approvals"}),e.jsxs(N,{onClick:()=>b(!0),children:[e.jsx(Y,{className:"h-4 w-4 mr-2"}),"Create Approvals"]})]}),e.jsxs("div",{className:"grid grid-cols-2 sm:grid-cols-4 gap-4",children:[e.jsx(R,{children:e.jsxs(M,{className:"pt-6 text-center",children:[e.jsx("p",{className:"text-2xl font-bold",children:f}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Total"})]})}),e.jsx(R,{children:e.jsxs(M,{className:"pt-6 text-center",children:[e.jsx("p",{className:"text-2xl font-bold",children:T}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Pending"})]})}),e.jsx(R,{children:e.jsxs(M,{className:"pt-6 text-center",children:[e.jsx("p",{className:"text-2xl font-bold",children:P}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Approved"})]})}),e.jsx(R,{children:e.jsxs(M,{className:"pt-6 text-center",children:[e.jsx("p",{className:"text-2xl font-bold",children:I}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Rejected"})]})})]}),e.jsxs(R,{children:[e.jsx(Ce,{children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs(Ae,{className:"flex items-center gap-2",children:[e.jsx(ye,{className:"h-5 w-5"}),"All Approvals"]}
6),e.jsx(Ne,{variant:"secondary",children:f})]})}),e.jsx(M,{children:u&&u.length>0?e.jsx("div",{className:"space-y-3",children:u.map(x=>{const j=Ue[x.kind],v=(j==null?void 0:j.icon)||te;return e.jsxs(me,{to:x.linkTo,className:"flex items-center justify-between p-3 bg-muted/50 rounded-lg hover:bg-muted transition-colors",children:[e.jsxs("div",{className:"flex items-center gap-3 min-w-0 flex-1",children:[e.jsx("div",{className:"p-2 bg-muted rounded-lg shrink-0",children:e.jsx(v,{className:"h-4 w-4 text-muted-foreground"})}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("p",{className:"font-medium text-sm truncate",children:x.title}),e.jsxs("div",{className:"flex items-center gap-2 mt-0.5",children:[e.jsx("span",{className:`inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium ${(j==null?void 0:j.badgeClass)||"bg-muted text-muted-foreground"}`,children:(j==null?void 0:j.label)||x.kind}),e.jsx("span",{className:"text-xs text-muted-foreground truncate",children:x.subtitle}),e.jsx("span",{className:"text-xs text-muted-foreground",children:"·"}),e.jsx("span",{className:"text-xs text-muted-foreground whitespace-nowrap",children:ne(new Date(x.createdAt),"MMM d, yyyy")})]})]})]}),e.jsx(De,{status:x.status,size:"sm"})]},x.id)})}):e.jsx("p",{className:"text-sm text-muted-foreground",children:"No approvals for this project"})})]}),e.jsx(Le,{open:w,onOpenChange:b,projectId:g.id})]})}export{dt 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.