PageSourceSearch

https://smartmanageai.ai/assets/projects-D0soID8T.js

js smartmanageai.ai collected 2026-10-05 15:06:25 UTC 45,723 bytes, 1 lines download raw bytes

1import{r as p,j as e}from"./vendor-react-DKbe1Umz.js";import{C as gt}from"./ContextualHelpButton-DKr5Uxvh.js";import{u as ft}from"./use-table-keyboard-nav-Updj1w8O.js";import{u as vt}from"./use-global-search-focus-B4gQZRid.js";import{a as Qe,ba as bt,M as Nt,N as wt,l as Q,Q as yt,B as V,C as Xe,v as Ze,u as Pe,bh as Ct,y as Ye,U as Ee,V as Me,W as Oe,b1 as Ie,Y as $e,X as Re,o as Ne,q as we,b7 as St,bi as kt,bj as Pt,bk as Lt,bg as At,bl as Tt,aK as Dt,bm as je,I as z,S as ne,g as re,h as ie,i as oe,j as U,D as Et,c as Mt,d as Ot,e as It,f as $t,aO as Rt,aP as I,aQ as $,aR as R,aS as F,aT as _,K as ge,L as le,T as Ft,n as _t,aW as Vt}from"./index-DZ74KeH3.js";import{T as Bt,a as zt,b as Fe,c as H,d as Ut,e as K}from"./table-CAeITjOT.js";import{C as _e}from"./checkbox-B-BhVsyi.js";import{S as Ve,H as ye,c as Gt,l as Ht,a as Kt,L as et,M as Be,T as ze,b as Ue,d as qt,u as Wt}from"./MapPickerDialog-CCOHBnSs.js";import{J as Ce,cZ as Se,n as tt,cr as Jt,a7 as Z,c0 as Ge,X as He,cE as Qt,b3 as Xt,a8 as Zt,dH as Yt,$ as es}from"./vendor-ui-DMaW9-Ov.js";import{u as Y,a as ts}from"./vendor-data-CjSe2wkl.js";import{V as ss,S as as}from"./SavedViewsDropdown-DFlCgdm0.js";import{a as ke,g as fe,h as ns,s as rs,e as is,l as os,m as Ke,n as ls,o as cs,q as ds,r as ms}from"./vendor-dates-5UNeOyFW.js";import{E as st}from"./EmptyState-B9ZWMRjO.js";import{C as qe}from"./CrmOrganizationSelector-CfmdFwur.js";import{A as us}from"./AIAnalysisButton-CMdEnjhw.js";import{A as hs,a as xs,b as ps,c as js,d as gs,e as fs,f as vs,g as bs}from"./alert-dialog-CA9oB9-z.js";import{a as Ns,t as ws}from"./vendor-forms-C2vWC2ab.js";import{c as ys,t as Cs}from"./crm-upgrade-Cd4-EfZp.js";import"./vendor-charts-DWX9qznF.js";const ee=p.memo(function({projectCode:h,summary:a}){const[,v]=Qe(),C=p.useCallback(()=>{v(`/projects/${h}?tab=plans`)},[h,v]),P=p.useCallback(g=>{g.stopPropagation(),C()},[C]),x=p.useCallback(g=>{(g.key==="Enter"||g.key===" ")&&(g.preventDefault(),g.stopPropagation(),C())},[C]);if(!a||a.newerSheetCount===0)return null;const{staleSetCount:L,newerSheetCount:N}=a,S=L===1?"set":"sets",u=N===1?"sheet":"sheets";return e.jsx(bt,{delayDuration:200,children:e.jsxs(Nt,{children:[e.jsx(wt,{asChild:!0,children:e.jsxs(Q,{variant:"outline",role:"button",tabIndex:0,onClick:P,onKeyDown:x,"aria-label":`${N} newer drawing ${u} available across ${L} ${S}`,className:"text-xs border-amber-400 bg-amber-50 text-amber-700 dark:bg-amber-900/20 dark:text-amber-400 cursor-pointer hover-elevate active-elevate-2","data-testid":`badge-project-stale-drawings-${h}`,children:[e.jsx(Ce,{className:"w-3 h-3 mr-0.5"}),N," newer"]})}),e.jsxs(yt,{children:[N," newer ",u," available across"," ",L," drawing ",S,". Click to open the Plans tab."]})]})})});function ce(i=!0){return Y({queryKey:["/api/projects/drawing-sets/stale-summary"],enabled:i,staleTime:6e4})}function Ss({projects:i,onRowClick:h,canDelete:a,onDelete:v,getRowProps:C,selectable:P,selectedIds:x,onToggleSelect:L,onToggleSelectAll:N}){const{data:S=[]}=Y({queryKey:["/api/project-health/overview"],refetchInterval:3e5}),u=new Map(S.map(r=>[r.project_id,r])),{data:g}=ce(i.length>0),y=(g==null?void 0:g.summary)??{};return e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"hidden md:block rounded-md border",children:e.jsxs(Bt,{children:[e.jsx(zt,{children:e.jsxs(Fe,{children:[P&&e.jsx(H,{className:"w-10",children:(()=>{const r=i.length,l=i.filter(m=>x==null?void 0:x.has(m.id)).length,n=r>0&&l===r,c=l>0&&!n,o=n?!0:c?"indeterminate":!1;return e.jsx(_e,{checked:o,onCheckedChange:m=>N==null?void 0:N(!!m),"aria-label":"Select all projects","data-testid":"checkbox-select-all-projects"})})()}),e.jsx(H,{className:"font-semibold",children:"Code"}),e.jsx(H,{className:"font-semibold",children:"Project Name"}),e.jsx(H,{className:"font-semibold",children:"Client"}),e.jsx(H,{className:"font-semibold",children:"Status"}),e.jsx(H,{className:"font-semibold",children:"Health"}),e.jsx(H,{className:"font-semibold",children:"Superintendent"}),e.jsx(H,{className:"font-semibold",children:"Estimator"}),a&&e.jsx(H,{className:"font-semibold w-16",children:"Actions"})]})}),e.jsx(Ut,{children:i.map((r,l)=>{const n=u.get(r.id);return e.jsxs(Fe,{className:"cursor-pointer hover-elevate",onClick:()=>h(r),"data-testid":`row-project-${r.code}`,...C?C(l):{},children:[P&&e.jsx(K,{onClick:c=>c.stopPropagation(),children:e.jsx(_e,{checked:!!(x!=null&&x.has(r.id)),onCheckedChange:c=>L==null?void 0:L(r.id,!!c),"aria-label":`Select project ${r.name}`,"data-testid":`checkbox-select-project-${r.code}`})}),e.jsx(K,{children:e.jsx(Q,{variant:"outline",className:"font-mono text-xs",children:r.code})}),e.jsx(K,{className:"font-medium",children:e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[e.jsx("span",{children:r.name}),e.jsx(ee,{projectCode:r.code,summary:y[r.id]})]})}),e.jsx(K,{children:r.clientName}),e.jsx(K,{children:e.jsx(Ve,{status:r.status,type:"project"})}),e.jsx(K,{children:n?e.jsx(ye,{score:n.overall_score,trendDirection:n.trend_direction,size:"sm",showTrend:!0}):e.jsx("span",{className:"text-xs text-muted-foreground",children:"—"})}),e.jsx(K,{className:"text-muted-foreground",children:r.superintendent||"—"}),e.jsx(K,{className:"text-muted-foreground",children:r.estimator||"—"}),a&&e.jsx(K,{children:e.jsx(V,{variant:"ghost",size:"icon",className:"text-destructive hover:text-destructive",onClick:c=>
1{c.stopPropagation(),v==null||v(r.code,r.name)},"data-testid":`button-delete-project-${r.code}`,children:e.jsx(Se,{className:"w-4 h-4"})})})]},r.id)})})]})}),e.jsx("div",{className:"md:hidden space-y-3",children:i.map(r=>{const l=u.get(r.id);return e.jsx(Xe,{className:"cursor-pointer active:scale-[0.98] transition-transform",onClick:()=>h(r),"data-testid":`card-project-${r.code}`,children:e.jsxs(Ze,{className:"p-4",children:[e.jsxs("div",{className:"flex items-start justify-between gap-2",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-1 flex-wrap",children:[e.jsx(Q,{variant:"outline",className:"font-mono text-xs shrink-0",children:r.code}),e.jsx(Ve,{status:r.status,type:"project"}),l&&e.jsx(ye,{score:l.overall_score,trendDirection:l.trend_direction,size:"sm"}),e.jsx(ee,{projectCode:r.code,summary:y[r.id]})]}),e.jsx("h3",{className:"font-medium text-sm leading-tight mb-1 truncate","data-testid":`text-project-name-${r.code}`,children:r.name}),r.clientName&&e.jsx("p",{className:"text-xs text-muted-foreground truncate","data-testid":`text-project-client-${r.code}`,children:r.clientName})]}),e.jsxs("div",{className:"flex items-center gap-1 shrink-0",children:[a&&e.jsx(V,{variant:"ghost",size:"icon",className:"h-8 w-8 text-destructive hover:text-destructive",onClick:n=>{n.stopPropagation(),v==null||v(r.code,r.name)},"data-testid":`button-delete-project-${r.code}`,children:e.jsx(Se,{className:"w-4 h-4"})}),e.jsx(tt,{className:"w-4 h-4 text-muted-foreground"})]})]}),(r.superintendent||r.estimator)&&e.jsxs("div",{className:"flex gap-4 mt-2 pt-2 border-t text-xs text-muted-foreground",children:[r.superintendent&&e.jsxs("span",{children:["Super: ",r.superintendent]}),r.estimator&&e.jsxs("span",{children:["Est: ",r.estimator]})]})]})},r.id)})})]})}const ve=[{key:"BID",label:"Bidding",accent:"bg-amber-500"},{key:"PLANNING",label:"Pre-Construction",accent:"bg-blue-500"},{key:"ACTIVE",label:"Active",accent:"bg-emerald-500"},{key:"COMPLETE",label:"Completed",accent:"bg-purple-500"},{key:"CLOSED",label:"Archived",accent:"bg-slate-500"}],We=["bg-rose-500","bg-orange-500","bg-amber-500","bg-emerald-500","bg-teal-500","bg-cyan-500","bg-blue-500","bg-indigo-500","bg-violet-500","bg-pink-500"];function ks(i){if(!i)return"bg-muted";let h=0;for(let a=0;a<i.length;a++)h=h*31+i.charCodeAt(a)|0;return We[Math.abs(h)%We.length]}function Ps(i){return i&&i.trim().split(/\s+/).slice(0,2).map(a=>{var v;return((v=a[0])==null?void 0:v.toUpperCase())||""}).join("")||"?"}function Ls(i){if(i==null||i==="")return"";const h=typeof i=="string"?Number(i):i;return Number.isNaN(h)?"":h.toLocaleString("en-US",{style:"currency",currency:"USD",maximumFractionDigits:0})}function As({projects:i,onCardClick:h}){const{toast:a}=Pe(),v=Ct(),[C,P]=p.useState(null),[x,L]=p.useState(null),{data:N=[]}=Y({queryKey:["/api/project-health/overview"],refetchInterval:3e5}),S=new Map(N.map(l=>[l.project_id,l])),{data:u}=ce(i.length>0),g=(u==null?void 0:u.summary)??{},y=ve.reduce((l,n)=>(l[n.key]=i.filter(c=>c.status===n.key),l),{}),r=async(l,n)=>{var m;l.preventDefault(),L(null);const c=l.dataTransfer.getData("text/plain");if(P(null),!c)return;const o=i.find(k=>k.code===c);if(!(!o||o.status===n))try{await v.mutateAsync({code:c,data:{status:n}}),a({title:"Project moved",description:`${o.name} → ${(m=ve.find(k=>k.key===n))==null?void 0:m.label}`})}catch(k){const D=k instanceof Error?k.message:"Could not change project status";a({title:"Failed to update",description:D,variant:"destructive"})}};return e.jsx("div",{className:"overflow-x-auto pb-2","data-testid":"view-kanban",children:e.jsx("div",{className:"flex gap-4 min-w-max",children:ve.map(l=>{const n=y[l.key],c=x===l.key;return e.jsxs("div",{className:`w-72 shrink-0 rounded-md border bg-muted/30 ${c?"ring-2 ring-primary":""}`,onDragOver:o=>{o.preventDefault(),L(l.key)},onDragLeave:()=>L(o=>
1o===l.key?null:o),onDrop:o=>r(o,l.key),"data-testid":`kanban-column-${l.key}`,children:[e.jsxs("div",{className:"flex items-center justify-between px-3 py-2 border-b",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:`w-2 h-2 rounded-full ${l.accent}`}),e.jsx("span",{className:"text-sm font-semibold",children:l.label})]}),e.jsx(Q,{variant:"secondary",className:"text-xs",children:n.length})]}),e.jsx("div",{className:"p-2 space-y-2 min-h-32 max-h-[calc(100vh-22rem)] overflow-y-auto",children:n.length===0?e.jsx("p",{className:"text-xs text-muted-foreground text-center py-6",children:"No projects"}):n.map(o=>{const m=S.get(o.id),k=o.superintendent||o.estimator||o.clientName,D=o.endDate||o.estimatedCompletionDate,G=C===o.code;return e.jsx(Xe,{draggable:!0,onDragStart:A=>{A.dataTransfer.setData("text/plain",o.code),A.dataTransfer.effectAllowed="move",P(o.code)},onDragEnd:()=>P(null),onClick:()=>h(o),className:`cursor-pointer hover-elevate ${G?"opacity-50":""}`,"data-testid":`kanban-card-${o.code}`,children:e.jsxs(Ze,{className:"p-3 space-y-2",children:[e.jsxs("div",{className:"flex items-start justify-between gap-2",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx(Q,{variant:"outline",className:"font-mono text-[10px] mb-1",children:o.code}),e.jsx("h4",{className:"text-sm font-medium leading-tight truncate","data-testid":`kanban-card-name-${o.code}`,children:o.name}),o.clientName&&e.jsx("p",{className:"text-xs text-muted-foreground truncate mt-0.5",children:o.clientName})]}),e.jsxs("div",{className:"flex items-center gap-1 shrink-0",children:[e.jsx(ee,{projectCode:o.code,summary:g[o.id]}),m&&e.jsx(ye,{score:m.overall_score,trendDirection:m.trend_direction,size:"sm"})]})]}),e.jsxs("div",{className:"flex items-center justify-between text-xs",children:[e.jsxs("div",{className:"flex items-center gap-2 min-w-0",children:[e.jsx("div",{className:`w-6 h-6 rounded-full flex items-center justify-center text-[10px] font-semibold text-white shrink-0 ${ks(k)}`,children:Ps(k)}),o.contractAmount&&e.jsx("span",{className:"text-muted-foreground truncate",children:Ls(o.contractAmount)})]}),D&&e.jsx("span",{className:"text-muted-foreground shrink-0",children:ke(new Date(D),"MMM d")})]})]})},o.id)})})]},l.key)})})})}const be={BID:"bg-amber-500 hover:bg-amber-600",PLANNING:"bg-blue-500 hover:bg-blue-600",ACTIVE:"bg-emerald-500 hover:bg-emerald-600",COMPLETE:"bg-purple-500 hover:bg-purple-600",CLOSED:"bg-slate-500 hover:bg-slate-600"};function Ts({projects:i,onProjectClick:h}){const[a,v]=p.useState(()=>fe(new Date)),{data:C}=ce(i.length>0),P=(C==null?void 0:C.summary)??{},x=p.useMemo(()=>i.map(n=>{const c=n.startDate?new Date(n.startDate):null,o=n.endDate??n.estimatedCompletionDate,m=o?new Date(o):null;return!c&&!m?null:{project:n,start:c||m,end:m||c}}).filter(n=>n!==null&&!isNaN(n.start.getTime())&&!isNaN(n.end.getTime())),[i]),L=fe(a),N=ns(a),S=rs(L),u=is(N),g=[];let y=S;for(;y<=u;){const n=[];for(let c=0;c<7;c++)n.push(y),y=os(y,1);g.push(n)}const r=g.map(n=>{const c=n[0],o=n[6],m=x.filter(A=>A.end>=c&&A.start<=o),k=[],D=[];m.sort((A,j)=>A.start.getTime()-j.start.getTime()).forEach(A=>{const j=Math.max(0,Ke(A.start,c)),M=Math.min(6,Ke(A.end,c)),T=M-j+1;let E=0;for(;;){if(!(D[E]||[]).some(b=>b>=j&&b<=M)){for(let b=j;b<=M;b++)(D[E]||(D[E]=[])).push(b);k.push({bar:A,startCol:j,span:T,row:E});return}E++}});const G=D.length;return{week:n,placed:k,maxRows:G}}),l=new Date;return e.jsxs("div",{className:"space-y-3","data-testid":"view-calendar",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("h2",{className:"text-lg font-semibold","data-testid":"calendar-month-label",children:ke(a,"MMMM yyyy")}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(V,{variant:"outline",size:"sm",onClick:()=>v(ls(a,1)),"data-testid":"calendar-prev",children:e.jsx(Jt,{className:"w-4 h-4"})}),e.jsx(V,{variant:"outline",size:"sm",onClick:()=>v(fe(new Date)),"data-testid":"calendar-today",children:"Today"}),e.jsx(V,{variant:"outline",size:"sm",onClick:()=>v(cs(a,1)),"data-testid":"calendar-next",children:e.jsx(tt,{className:"w-4 h-4"})})]})]}),e.jsxs("div",{className:"rounded-md border overflow-hidden",children:[e.jsx("div",{className:"grid grid-cols-7 bg-muted/40 text-xs font-medium text-muted-foreground",children:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"].map(n=>e.jsx("div",{className:"px-2 py-1.5 text-center border-r last:border-r-0",children:n},n))}),e.jsx("div",{className:"divide-y",children:r.map(({week:n,placed:c,maxRows:o},m)=>{const A=22+Math.max(o,1)*18+6;return e.jsxs("div",{className:"relative grid grid-cols-7",style:{minHeight:A},children:[n.map((j,M)=>{const T=ds(j,a),E=ms(j,l);return e.jsx("div",{className:`border-r last:border-r-0 px-1.5 pt-1 ${T?"bg-background":"bg-muted/20"}`,children:e.jsx("div",{className:`text-xs ${E?"inline-flex w-5 h-5 items-center justify-center rounded-full bg-primary text-primary-foreground font-semibold":T?"text-foreground":"text-muted-foreground"}`,children:ke(j,"d")})},M)}),c.map(({bar:j,startCol:M,span:T,row:E},s)=>{const w=j.project.status,b=be[w]||"bg-slate-500 hover:bg-slate-600",te=P[j.project.id];return e.jsxs("button",{type:"button",onClick:()=>h(j.project),className:`absolute flex items-center gap-1 text-[11px] text-white px-1.5 py-0.5 rounded text-left ${b}`,style:{left:`calc(${M/7*100}% + 2px)`,width:`calc(${T/7*100}% - 4px)`,top:22+E*18,height:16},title:`${j.project.name} (${j.project.code})`,"data-testid":`calendar-bar-${j.project.code}`,children:[e.jsx("span",{className:"flex-1 min-w-0 truncate",children:j.project.name}),e.jsx(ee,{projectCode:j.project.code,summary:te})]},s)})]},m)})})]}),e.jsx("div",{className:"flex flex-wrap items-center gap-3 text-xs text-muted-foreground",children:Object.keys(be).map(n=>e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:`inline-block w-3 h-3 rounded ${be[n].split(" ")[0]}`}),e.jsx("span",{children:n})]},n))})]})}const Ds=Gt(function(h,a){const v=new Ht.Popup(h,a.overlayContainer);return Kt(v,a)},function(h,a,{position:v},C){p.useEffect(function(){const{instance:x}=h;function L(S){S.popup===x&&(x.update(),C(!0))}function N(S){S.popup===x&&C(!1)}return a.map.on({popupopen:L,popupclose:N}),a.overlayContainer==null?(v!=null&&x.setLatLng(v),x.openOn(a.map)):a.overlayContainer.bindPopup(x),function(){var u;a.map.off({popupopen:L,popupclose:N}),(u=a.overlayContainer)==null||u.unbindPopup(),a.map.removeLayer(x)}},[h,a,C,v])}),Es=new et.Icon({iconUrl:"https://unpkg.com/[email protected]/dist/images/marker-icon.png",iconRetinaUrl:"https://unpkg.com/[email protected]/dist/images/marker-icon-2x.png",shadowUrl:"https://unpkg.com/[email protected]/dist/images/marker-shadow.png",iconSize:[25,41],iconAnchor:[12,41],popupAnchor:[1,-34],shadowSize:[41,41]});function Je({onContext:i}){return Wt({contextmenu(h){h.originalEvent.preventDefault(),i(h.latlng.lat,h.latlng.lng,{x:h.containerPoint.x,y:h.containerPoint.y})}}),null}function Ms({projects:i,onProjectClick:h}){const{user:a}=Ye(),{toast:v}=Pe(),[C,P]=p.useState(!1);p.useEffect(()=>{et.Marker.prototype.options.icon=Es},[]);const{data:x}=ce(i.length>0),L=(x==null?void 0:x.summary)??{},N=p.useMemo(()=>i.filter(s=>typeof s.siteLatitude=="number"&&typeof s.siteLongitude=="number"&&!isNaN(s.siteLatitude)&&!isNaN(s.siteLongitude)),[i]),S=(a==null?void 0:a.role)==="ADMIN"||(a==null?void 0:a.role)==="MANAGER"||(a==null?void 0:a.role)==="SUPER_ADMIN",u=S,g=p.useMemo(()=>i.filter(s=>typeof s.siteLatitude!="number"||typeof s.siteLongitude!="number"||isNaN(s.siteLatitude)||isNaN(s.siteLongitude)),[i]),y=i.length-N.length,r=s=>!!(s.locationAddress&&s.locationAddress.trim()||s.city&&s.city.trim()),l=p.useMemo(()=>i.filter(s=>(s.siteLatitude==null||s.siteLongitude==null)&&r(s)).length,[i]),n=p.useMemo(()=>i.filter(s=>(s.siteLatitude==null||s.siteLongitude==null)&&r(s)&&(s.lastGeocodeStatus==="NOT_FOUND"||s.lastGeocodeStatus==="FAILED")),[i]),[c,o]=p.useState(null),[m,k]=p.useState(null),[D,G]=p.useState(!1),A=async()=>
1{if(!C){P(!0);try{const w=await(await Ne("POST","/api/projects/geocode-pending",{})).json();v({title:"Geocoding complete",description:`Scanned ${w.scanned}, located ${w.geocoded}, not found ${w.notFound}, failed ${w.failed}.`}),await we.invalidateQueries({queryKey:["/api/projects"]})}catch(s){v({title:"Geocoding failed",description:s instanceof Error?s.message:String(s),variant:"destructive"})}finally{P(!1)}}},j=(s,w,b)=>{o(null),k({project:s,initialLat:w,initialLng:b})},M=async(s,w)=>{if(m){G(!0);try{await Ne("PATCH",`/api/projects/${m.project.code}`,{siteLatitude:s,siteLongitude:w}),await we.invalidateQueries({queryKey:["/api/projects"]}),v({title:"Location saved",description:`${m.project.code} pinned at ${s.toFixed(6)}, ${w.toFixed(6)}.`}),k(null)}catch(b){v({title:"Failed to save location",description:b instanceof Error?b.message:String(b),variant:"destructive"})}finally{G(!1)}}},T=N.length?[N.reduce((s,w)=>s+w.siteLatitude,0)/N.length,N.reduce((s,w)=>s+w.siteLongitude,0)/N.length]:[39.8283,-98.5795];if(N.length===0)return e.jsxs("div",{className:"space-y-3","data-testid":"view-map",children:[n.length>0&&e.jsxs("div",{className:"flex items-start gap-2 rounded-md border border-amber-300 bg-amber-50 dark:border-amber-700 dark:bg-amber-950/40 px-3 py-2 text-xs","data-testid":"banner-unresolved-addresses",children:[e.jsx(Ce,{className:"h-4 w-4 mt-0.5 text-amber-600 dark:text-amber-400 shrink-0"}),e.jsxs("div",{children:[e.jsxs("span",{className:"font-medium text-amber-900 dark:text-amber-200",children:[n.length," project address",n.length===1?"":"es"," couldn't be located."]})," ",e.jsxs("span",{className:"text-amber-800/80 dark:text-amber-200/70",children:["Update the address on"," ",n.slice(0,3).map((s,w)=>e.jsxs("span",{children:[w>0&&", ",e.jsx("span",{className:"font-mono",children:s.code})]},s.id)),n.length>3&&` and ${n.length-3} more`," ","to retry automatically."]})]})]}),e.jsx(st,{icon:Z,title:"No projects on the map yet",description:l>0?`${l} project(s) have an address but no coordinates. Click below to look them up automatically, or right-click the map to drop a pin manually.`:u&&g.length>0?"Right-click anywhere on the map below to drop a pin and set a location for one of your projects.":"Add a site latitude and longitude to a project (Project → Settings → Location) — or open a project and use Pick on map — and it will show up here as a pin."}),S&&l>0&&e.jsx("div",{className:"flex justify-center",children:e.jsx(V,{onClick:A,disabled:C,"data-testid":"button-geocode-projects",children:C?e.jsxs(e.Fragment,{children:[e.jsx(Ge,{className:"mr-2 h-4 w-4 animate-spin"}),"Locating addresses…"]}):e.jsxs(e.Fragment,{children:[e.jsx(Z,{className:"mr-2 h-4 w-4"}),"Locate ",l," project address",l===1?"":"es"]})})}),u&&g.length>0&&e.jsx("div",{className:"rounded-md border overflow-hidden relative","data-testid":"empty-map-picker",children:e.jsxs("div",{className:"h-[50vh] min-h-80 w-full relative",children:[e.jsxs(Be,{center:T,zoom:4,scrollWheelZoom:!0,className:"h-full w-full",children:[e.jsx(ze,{attribution:'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>',url:"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"}),e.jsx(Je,{onContext:(s,w,b)=>o({lat:s,lng:w,x:b.x,y:b.y})})]}),c&&e.jsx("div",{className:"absolute z-[1000]",style:{left:c.x,top:c.y},children:e.jsxs(Ee,{open:!0,onOpenChange:s=>{s||o(null)},children:[e.jsx(Me,{asChild:!0,children:e.jsx("span",{className:"block w-px h-px"})}),e.jsxs(Oe,{align:"start",className:"w-72","data-testid":"menu-set-location-for-project",children:[e.jsxs(Ie,{className:"text-xs font-normal text-muted-foreground",children:["Set location at ",c.lat.toFixed(5),","," ",c.lng.toFixed(5)," for…"]}),e.jsx($e,{}),g.slice(0,12).map(s=>e.jsxs(Re,{onSelect:()=>{j(s,c.lat,c.lng)},"data-testid":`menu-item-set-location-${s.code}`,children:[e.jsx(Z,{className:"mr-2 h-3.5 w-3.5"}),e.jsx("span",{className:"font-mono text-xs mr-2",children:s.code}),e.jsx("span",{className:"truncate",children:s.name})]},s.id)),g.length>12&&e.jsxs("div",{className:"px-2 py-1 text-[10px] text-muted-foreground",children:["Showing first 12 of ",g.length," unlocated projects."]})]})]})})]})}),m&&e.jsx(Ue,{open:!!m,onOpenChange:s=>{s||k(null)},initialLat:m.initialLat,initialLng:m.initialLng,title:`Set location for ${m.project.code}`,description:`Click the map or drag the pin to set the exact site location for ${m.project.name}.`,isSaving:D,onConfirm:M})]});const E=n.length>0&&e.jsxs("div",{className:"flex items-start gap-2 rounded-md border border-amber-300 bg-amber-50 dark:border-amber-700 dark:bg-amber-950/40 px-3 py-2 text-xs","data-testid":"banner-unresolved-addresses",children:[e.jsx(Ce,{className:"h-4 w-4 mt-0.5 text-amber-600 dar
1k:text-amber-400 shrink-0"}),e.jsxs("div",{className:"space-y-1",children:[e.jsxs("div",{className:"font-medium text-amber-900 dark:text-amber-200",children:[n.length," project address",n.length===1?"":"es"," couldn't be located"]}),e.jsxs("div",{className:"text-amber-800/80 dark:text-amber-200/70",children:["Check the address on"," ",n.slice(0,3).map((s,w)=>e.jsxs("span",{"data-testid":`text-unresolved-${s.code}`,children:[w>0&&", ",e.jsx("span",{className:"font-mono",children:s.code})]},s.id)),n.length>3&&` and ${n.length-3} more`," ","so it can be re-tried automatically."]})]})]});return e.jsxs("div",{className:"space-y-3","data-testid":"view-map",children:[E,e.jsxs("div",{className:"rounded-md border overflow-hidden relative",children:[e.jsxs("div",{className:"h-[60vh] min-h-96 w-full relative",children:[e.jsxs(Be,{center:T,zoom:N.length===1?11:5,scrollWheelZoom:!0,className:"h-full w-full",children:[e.jsx(ze,{attribution:'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>',url:"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"}),u&&g.length>0&&e.jsx(Je,{onContext:(s,w,b)=>o({lat:s,lng:w,x:b.x,y:b.y})}),N.map(s=>e.jsx(qt,{position:[s.siteLatitude,s.siteLongitude],"data-testid":`map-pin-${s.code}`,children:e.jsx(Ds,{children:e.jsxs("div",{className:"space-y-1",children:[e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[e.jsx("div",{className:"font-mono text-xs text-muted-foreground",children:s.code}),e.jsx(ee,{projectCode:s.code,summary:L[s.id]})]}),e.jsx("div",{className:"font-medium text-sm",children:s.name}),s.clientName&&e.jsx("div",{className:"text-xs",children:s.clientName}),e.jsx("button",{type:"button",className:"text-xs text-primary hover:underline",onClick:()=>h(s),"data-testid":`map-open-${s.code}`,children:"Open project →"}),u&&e.jsx("button",{type:"button",className:"text-xs text-primary hover:underline block",onClick:()=>j(s,s.siteLatitude,s.siteLongitude),"data-testid":`map-relocate-${s.code}`,children:"Move pin…"})]})})},s.id))]}),c&&u&&g.length>0&&e.jsx("div",{className:"absolute z-[1000]",style:{left:c.x,top:c.y},children:e.jsxs(Ee,{open:!0,onOpenChange:s=>{s||o(null)},children:[e.jsx(Me,{asChild:!0,children:e.jsx("span",{className:"block w-px h-px"})}),e.jsxs(Oe,{align:"start",className:"w-72","data-testid":"menu-set-location-for-project",children:[e.jsxs(Ie,{className:"text-xs font-normal text-muted-foreground",children:["Set location at ",c.lat.toFixed(5),","," ",c.lng.toFixed(5)," for…"]}),e.jsx($e,{}),g.slice(0,12).map(s=>e.jsxs(Re,{onSelect:()=>{j(s,c.lat,c.lng)},"data-testid":`menu-item-set-location-${s.code}`,children:[e.jsx(Z,{className:"mr-2 h-3.5 w-3.5"}),e.jsx("span",{className:"font-mono text-xs mr-2",children:s.code}),e.jsx("span",{className:"truncate",children:s.name})]},s.id)),g.length>12&&e.jsxs("div",{className:"px-2 py-1 text-[10px] text-muted-foreground",children:["Showing first 12 of ",g.length," unlocated projects."]})]})]})})]}),y>0&&e.jsxs("div",{className:"px-3 py-2 text-xs border-t bg-muted/30 flex items-center justify-between gap-3 flex-wrap",children:[e.jsxs("span",{className:"text-muted-foreground",children:["Showing ",N.length," of ",i.length," projects. ",y," project(s) are missing site coordinates.",u&&g.length>0&&" Right-click anywhere on the map to set a location for one of them."]}),S&&l>0&&e.jsx(V,{size:"sm",variant:"outline",onClick:A,disabled:C,"data-testid":"button-geocode-projects",children:C?e.jsxs(e.Fragment,{children:[e.jsx(Ge,{className:"mr-2 h-3 w-3 animate-spin"}),"Locating…"]}):e.jsxs(e.Fragment,{children:[e.jsx(Z,{className:"mr-2 h-3 w-3"}),"Locate ",l," address",l===1?"":"es"]})})]})]}),m&&e.jsx(Ue,{open:!!m,onOpenChange:s=>{s||k(null)},initialLat:m.initialLat,initialLng:m.initialLng,title:`Set location for ${m.project.code}`,description:`Click the map or drag the pin to set the exact site location for ${m.project.name}.`,isSaving:D,onConfirm:M})]})}const Os={status:"ALL",search:"",special:null},Is=[{id:"builtin-all",name:"All projects",apply:{view:"table",filters:{status:"ALL",search:"",special:null}}}
1,{id:"builtin-active",name:"My active projects",apply:{view:"table",filters:{status:"ACTIVE",search:"",special:"myProjects"}}},{id:"builtin-bidding",name:"Bidding",apply:{view:"kanban",filters:{status:"BID",search:"",special:null}}},{id:"builtin-onhold",name:"On hold > 14 days",apply:{view:"table",filters:{status:"PLANNING",search:"",special:"onHoldStale14"}}}];function ta(){const[,i]=Qe(),h=St(),{user:a,logout:v,organizationName:C}=Ye(),{toast:P}=Pe(),[x,L]=p.useState(""),N=p.useRef(null),S=kt(a==null?void 0:a.role),[u,g]=p.useState("ALL"),[y,r]=p.useState(null),[l,n]=p.useState(()=>{if(typeof window>"u")return"table";const t=window.localStorage.getItem("projects-view");return t==="kanban"||t==="calendar"||t==="map"||t==="table"?t:"table"});p.useEffect(()=>{typeof window<"u"&&window.localStorage.setItem("projects-view",l)},[l]);const c=t=>{n(t.view),g(t.filters.status||"ALL"),L(t.filters.search||""),r(t.filters.special??null)},[o,m]=p.useState(!1),k=Pt(),D=Lt(),[G,A]=p.useState(!1),[j,M]=p.useState(null),[T,E]=p.useState(null),[s,w]=p.useState(null),[b,te]=p.useState(null),[de,me]=p.useState(null),at=(a==null?void 0:a.role)==="ADMIN"||(a==null?void 0:a.role)==="MANAGER";p.useEffect(()=>{const t=new URLSearchParams(h);t.get("new")==="true"&&(m(!0),i("/projects",{replace:!0}));const d=t.get("status");d&&["ACTIVE","PLANNING","COMPLETE","CLOSED"].includes(d)&&g(d),t.get("changeOrders")==="pending"?r("pendingChangeOrders"):t.get("filter")==="missingBudget"&&r("missingBudget")},[h,i]);const nt=ys.omit({code:!0}),f=Ns({resolver:ws(nt),defaultValues:{name:"",clientName:"",clientContactName:"",clientContactEmail:"",clientContactPhone:"",status:"PLANNING",budget:"",contractAmount:"",locationAddress:"",city:"",state:"",description:"",gcOrganizationId:void 0,ownerRepOrganizationId:void 0,programId:"",divisionId:"",primaryTradeType:void 0}}),rt=t=>{const d=T==null?void 0:T.id;E(t),(!t||t.id!==d)&&(w(null),f.setValue("clientContactName",""),f.setValue("clientContactEmail",""),f.setValue("clientContactPhone","")),t?(f.setValue("gcOrganizationId",t.id),f.setValue("clientName",t.name)):(f.setValue("gcOrganizationId",void 0),f.setValue("clientName",""))},it=t=>{if(w(t),t){const d=`${t.firstName} ${t.lastName}`.trim();f.setValue("clientContactName",d),f.setValue("clientContactEmail",t.email||""),f.setValue("clientContactPhone",t.phone||t.mobile||"")}else f.setValue("clientContactName",""),f.setValue("clientContactEmail",""),f.setValue("clientContactPhone","")},ot=t=>{const d=b==null?void 0:b.id;te(t),(!t||t.id!==d)&&me(null),t?f.setValue("ownerRepOrganizationId",t.id):f.setValue("ownerRepOrganizationId",void 0)},lt=t=>{me(t)},Le=t=>{m(t),t||Ae()},Ae=()=>{f.reset(),E(null),w(null),te(null),me(null)},ct=async t=>{try{const d={...t,clientName:t.clientName||void 0,clientContactName:t.clientContactName||void 0,clientContactEmail:t.clientContactEmail||void 0,clientContactPhone:t.clientContactPhone||void 0,budget:t.budget||void 0,contractAmount:t.contractAmount||void 0,locationAddress:t.locationAddress||void 0,city:t.city||void 0,state:t.state||void 0,description:t.description||void 0,gcOrganizationId:(T==null?void 0:T.id)||void 0,ownerRepOrganizationId:(b==null?void 0:b.id)||void 0,programId:t.programId||void 0,divisionId:t.divisionId||void 0,primaryTradeType:t.primaryTradeType||void 0},O=await k.mutateAsync(d);O&&O.code&&(P({title:"Success",description:`Project ${O.code} created successfully!`}),m(!1),Ae(),i(`/projects/${O.code}`))}catch(d){P({title:"Error",description:d.message||"Failed to create project",variant:"destructive"})}},dt=(t,d)=>{M({code:t,name:d}),A(!0)},mt=async()=>{if(j)try{await D.mutateAsync(j.code),P({title:"Success",description:`Project ${j.code} has been deleted.`}),A(!1),M(null)}catch(t){P({title:"Error",description:t.message||"Failed to delete project",variant:"destructive"})}},{data:ut=[],isLoading:ht}=At(),ue=(a==null?void 0:a.role)==="ADMIN"||(a==null?void 0:a.role)==="MANAGER"||(a==null?void 0:a.role)==="ESTIMATOR",Te=[{value:"projectManagerId",label:"Project Manager"},{value:"superintendentId",label:"Superintendent"},{value:"estimatorId",label:"Estimator"},{value:"safetyOfficerId",label:"Safety Officer"}
1],[se,X]=p.useState(new Set),[De,xt]=p.useState("projectManagerId"),{data:he=[]}=Y({queryKey:["/api/users"],enabled:ue}),xe=new Map(he.map(t=>{const d=`${t.firstName??""} ${t.lastName??""}`.trim();return[t.id,d||t.email||t.id]})),ae=ts({mutationFn:async({projectIds:t,roleField:d,userId:O})=>(await Ne("POST","/api/projects/bulk-reassign-owner",{projectIds:t,roleField:d,userId:O})).json(),onSuccess:(t,d)=>{var B;we.invalidateQueries({queryKey:["/api/projects"]}),X(new Set);const O=((B=Te.find(pe=>pe.value===d.roleField))==null?void 0:B.label)??"owner",W=d.userId?xe.get(d.userId)??"selected user":"Unassigned",J=(t==null?void 0:t.updated)??0;P({title:`Reassigned ${J} project${J===1?"":"s"}`,description:`${O} → ${W}`})},onError:t=>{const d=t instanceof Error?t.message:"";P({title:"Failed to reassign owner",description:d,variant:"destructive"})}}),{data:pt=[]}=Y({queryKey:["/api/projects/with-pending-change-orders"],enabled:y==="pendingChangeOrders"}),q=ut.filter(t=>{const d=t.name.toLowerCase().includes(x.toLowerCase())||t.code.toLowerCase().includes(x.toLowerCase())||t.clientName&&t.clientName.toLowerCase().includes(x.toLowerCase()),O=u==="ALL"||t.status===u,W=Tt(a==null?void 0:a.role,t.status);let J=!0;if(y==="pendingChangeOrders")J=pt.includes(t.id);else if(y==="missingBudget"){const B=Number(t.budget);J=!t.budget||isNaN(B)||B<=0}else if(y==="myProjects"){const B=a==null?void 0:a.id;J=!!B&&(t.estimatorId===B||t.superintendentId===B||t.projectManagerId===B)}else if(y==="onHoldStale14"){const B=t.updatedAt?new Date(t.updatedAt).getTime():0,pe=Date.now()-14*24*60*60*1e3;J=B>0&&B<pe}return d&&O&&W&&J}),{getRowProps:jt}=ft({rowCount:q.length,onActivate:t=>{const d=q[t];d&&i(`/projects/${d.code}`)}});return vt(N),Dt("projects-list",Vt),e.jsxs("div",{className:"min-h-screen bg-background",children:[e.jsxs("main",{className:"mx-auto max-w-full px-4 sm:px-6 py-6 sm:py-8",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-6 sm:mb-8",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-xl sm:text-2xl font-bold text-foreground mb-1",children:y==="pendingChangeOrders"?"Projects with Pending Change Orders":y==="missingBudget"?"Projects Missing Budget Data":u!=="ALL"?`${u.charAt(0)+u.slice(1).toLowerCase()} Projects`:"All Projects"}),e.jsx("p",{className:"text-xs sm:text-sm text-muted-foreground",children:y==="pendingChangeOrders"?"Projects with change orders awaiting client response":y==="missingBudget"?"Projects that need budget information added":"View and manage all awarded construction projects"}),(y||u!=="ALL")&&e.jsxs("div",{className:"flex items-center gap-2 mt-2",children:[u!=="ALL"&&e.jsxs(Q,{variant:"secondary",className:"gap-1",children:["Status: ",u,e.jsx(He,{className:"w-3 h-3 cursor-pointer",onClick:()=>g("ALL"),"data-testid":"button-clear-status-filter"})]}),y&&e.jsxs(Q,{variant:"secondary",className:"gap-1",children:[y==="pendingChangeOrders"?"Pending COs":"Missing Budget",e.jsx(He,{className:"w-3 h-3 cursor-pointer",onClick:()=>{r(null),i("/projects",{replace:!0})},"data-testid":"button-clear-special-filter"})]})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-2 items-center",children:[e.jsx(gt,{}),e.jsx(ss,{value:l,onChange:n,testId:"projects-view-switcher"}),e.jsx(as,{viewKey:"projects",builtInViews:Is,defaultFilters:Os,current:{view:l,filters:{status:u,search:x,special:y}},onApply:c}),e.jsx(us,{showDropdown:!0}),je.CREATE_PROJECT(a==null?void 0:a.role)&&e.jsxs(e.Fragment,{children:[e.jsx(V,{variant:"outline",onClick:()=>i("/bids"),"data-testid":"button-view-bids",children:"View Bids"}),e.jsxs(V,{variant:"outline",onClick:()=>i("/templates/projects"),"data-testid":"button-from-template",children:[e.jsx(Qt,{className:"w-4 h-4 mr-1 sm:mr-2"}),"From Template"]}),e.jsxs(V,{onClick:()=>m(!0),"data-testid":"button-new-project",children:[e.jsx(Xt,{className:"w-4 h-4 mr-1 sm:mr-2"}),"New Project"]})]})]})]}),e.jsxs("div",{className:"flex flex-col md:flex-row gap-4 mb-6",children:[e.jsxs("div",{className:"relative flex-1",children:[e.jsx(Zt,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground"}),e.jsx(z,{ref:N,placeholder:"Search projects by name, code, or client...",className:"pl-9",value:x,onChange:t=>L(t.target.value),"data-testid":"input-search"})]}),e.jsxs(ne,{value:u,onValueChange:g,children:[e.jsx(re,{className:"w-full md:w-48","data-testid":"select-status-filter",children:e.jsx(ie,{placeholder:"Filter by status"})}),e.jsxs(oe,{children:[e.jsx(U,{value:"ALL",children:"All Statuses"}),S.includes("PLANNING")&&e.jsx(U,{value:"PLANNING",children:"Planning"}),S.includes("ACTIVE")&&e.jsx(U,{value:"ACTIVE",children:"Active"}),S.includes("COMPLETE")&&e.jsx(U,{value:"COMPLETE",children:"Complete"}),S.includes("CLOSED")&&e.jsx(U,{value:"CLOSED",children:"Closed"})]})]})]}),ht?e.jsx("div",{className:"text-center py-12 text-muted-foreground",children:"Loading projects..."}):q.length===0&&l==="table"?e.jsx(st,{icon:Yt,title:x||u!=="ALL"?"No projects match your filters":"No projects yet",description:x||u!=="ALL"?"Try adjusting your search or filter criteria.":"Create your first project to start tracking construction work.",actionLabel:!(x||u!=="ALL")&&je.CREATE_PROJECT(a==null?void 0:a.role)?"New Project":void 0,onAction:!(x||u!=="ALL")&&je.CREATE_PROJECT(a==null?void 0:a.role)?()=>m(!0):void 0}):l==="kanban"?e.jsx(As,{projects:q,onCardClick:t=>i(`/projects/${t.code}`)}):l==="calendar"?e.jsx(Ts,{projects:q,onProjectClick:t=>i(`/projects/${t.code}`)}):l==="map"?e.jsx(Ms,{projects:q,onProjectClick:t=>i(`/projects/${t.code}`)}):e.jsxs("div",{className:"space-y-3",children:[ue&&se.size>0&&e.jsxs("div",{className:"flex flex-wrap items-center gap-2 rounded-md border bg-muted/30 px-4 py-3","data-testid":"bulk-project-actions",children:[e.jsx(es,{className:"w-4 h-4 text-muted-foreground"}),e.jsxs(Q,{variant:"default",className:"text-xs",children:[se.size," selected"]}),e.jsx("span",{className:"text-sm text-muted-foreground ml-1",children:"Reassign"}),e.jsxs(ne,{value:De,onValueChange:t=>xt(t),disabled:ae.isPending,children:[e.jsx(re,{className:"h-8 w-[180px]","data-testid":"select-bulk-project-role",children:e.jsx(ie,{})}),e.jsx(oe,{children:Te.map(t=>e.jsx(U,{value:t.value,"data-testid":`option-bulk-project-role-${t.value}`,children:t.label},t.value))})]}),e.jsx("span",{className:"text-sm text-muted-foreground",children:"to"}),e.jsxs(ne,{value:"",onValueChange:t=>{if(!t)return;const d=Array.from(se),O=t==="__unassigned__"?null:t;ae.mutate({projectIds:d,roleField:De,userId:O})},disabled:ae.isPending,children:[e.jsx(re,{className:"h-8 w-[220px]","data-testid":"select-bulk-project-user",children:e.jsx(ie,{placeholder:ae.isPending?"Reassigning...":"Select user..."})}),e.jsxs(oe,{children:[e.jsx(U,{value:"__unassigned__","data-testid":"option-bulk-project-user-unassigned",children:"Unassigned"}),(a==null?void 0:a.id)&&he.some(t=>t.id===a.id)&&e.jsxs(U,{value:a.id,"data-testid":"option-bulk-project-user-mine",children:["Me (",xe.get(a.id)??"current user",")"]}),he.filter(t=>t.id!==(a==null?void 0:a.id)).map(t=>e.jsx(U,{value:t.id,"data-testid":`option-bulk-project-user-${t.id}`,children:xe.get(t.id)??t.id},t.id))]})]}),e.jsx(V,{size:"sm",variant:"ghost",onClick:()=>X(new Set),"data-testid":"button-clear-project-selection",children:"Clear"})]}),e.jsx(Ss,{projects:q,onRowClick:t=>i(`/projects/${t.code}`),canDelete:at,onDelete:dt,getRowProps:jt,selectable:ue,selectedIds:se,onToggleSelect:(t,d)=>X(O=>{const W=new Set(O);return d?W.add(t):W.delete(t),W}),onToggleSelectAll:t=>{X(t?new Set(q.map(d=>d.id)):new Set)}})]})]}),e.jsx(Et,{open:o,onOpenChange:Le,children:e.jsxs(Mt,{className:"sm:max-w-2xl","data-testid":"dialog-create-project",children:[e.jsxs(Ot,{children:[e.jsx(It,{children:"Create New Project"}),e.jsx($t,{children:"Create a new project directly. For projects from won bids, use the Bid Board to convert."})]}),e.jsxs("div",{className:"rounded-md border bg-muted/40 p-3 flex items-center justify-between gap-3","data-testid":"banner-start-from-template",children:[e.jsxs("div",{className:"text-sm",children:[e.jsx("div",{className:"font-medium",children:"Start from a template?"}),e.jsx("div",{className:"text-muted-foreground",children:"Pre-fill schedule, dependencies, distribution lists, and SoV from a saved template."})]}),e.jsx(V,{type:"button",variant:"outline",size:"sm",onClick:()=>{m(!1),i("/templates/projects")},"data-testid":"button-wizard-from-template",children:"Browse Templates"})]}),e.jsx(Rt,{...f,children:e.jsxs("form",{onSubmit:f.handleSubmit(ct),className:"space-y-4",children:[e.jsx(I,{control:f.control,name:"name",render:({field:t})=>e.jsxs($,{children:[e.jsx(R,{children:"Project Name *"}),e.jsx(F,{children:e.jsx(z,{placeholder:"Downtown Office Renovation",...t,"data-testid":"input-project-name"})}),e.jsx(_,{})]})}),e.jsx(ge,{className:"my-2"}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(le,{className:"text-sm font-medium",children:"CRM Integration"}),e.jsx("span",{className:"text-xs text-muted-foreground",children:"Select from CRM to auto-fill client info"})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(le,{className:"text-sm",children:"GC / General Contractor"}),e.jsx(qe,{value:T==null?void 0:T.id,onSelect:rt,onContactSelect:it,filterTypes:["CONTRACTOR"],placeholder:"Select GC...",showContactSelector:!0,selectedContactId:s==null?void 0:s.id})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(le,{className:"text-sm",children:"Owner Representative"}),e.jsx(qe,{value:b==null?void 0:b.id,onSelect:ot,onContactSelect:lt,filterTypes:["OWNER_REP"],placeholder:"Select Owner Rep...",showContactSelector:!0,selectedContactId:de==null?void 0:de.id})]})]})]}),e.jsx(ge,{className:"my-2"}),e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsx(I,{control:f.control,name:"clientName",render:({field:t})=>e.jsxs($,{children:[e.jsx(R,{children:"Client Name"}),e.jsx(F,{children:e.jsx(z,{placeholder:"Acme Corporation",...t,value:t.value||"","data-testid":"input-client-name"})}),e.jsx(_,{})]})}),e.jsx(I,{control:f.control,name:"clientContactName",render:({field:t})=>e.jsxs($,{children:[e.jsx(R,{children:"Contact Name"}),e.jsx(F,{children:e.jsx(z,{placeholder:"John Smith",...t,value:t.value||"","data-testid":"input-contact-name"})}),e.jsx(_,{})]})})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsx(I,{control:f.control,name:"clientContactEmail",render:({field:t})=>e.jsxs($,{children:[e.jsx(R,{children:"Contact Email"}),e.jsx(F,{children:e.jsx(z,{type:"email",placeholder:"[email protected]",...t,value:t.value||"","data-testid":"input-contact-email"})}),e.jsx(_,{})]})}),e.jsx(I,{control:f.control,name:"clientContactPhone",render:({field:t})=>e.jsxs($,{children:[e.jsx(R,{children:"Contact Phone"}),e.jsx(F,{children:e.jsx(z,{placeholder:"(555) 123-4567",...t,value:t.value||"","data-testid":"input-contact-phone"})}),e.jsx(_,{})]})})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsx(I,{control:f.control,name:"budget",render:({field:t})=>e.jsxs($,{children:[e.jsx(R,{children:"Budget"}),e.jsx(F,{children:e.jsx(z,{type:"number",step:"0.01",placeholder:"250000.00",...t,value:t.value||"","data-testid":"input-budget"})}),e.jsx(_,{})]})}
1),e.jsx(I,{control:f.control,name:"contractAmount",render:({field:t})=>e.jsxs($,{children:[e.jsx(R,{children:"Contract Amount"}),e.jsx(F,{children:e.jsx(z,{type:"number",step:"0.01",placeholder:"275000.00",...t,value:t.value||"","data-testid":"input-contract-amount"})}),e.jsx(_,{})]})})]}),e.jsxs("div",{className:"grid grid-cols-3 gap-4",children:[e.jsx(I,{control:f.control,name:"locationAddress",render:({field:t})=>e.jsxs($,{children:[e.jsx(R,{children:"Address"}),e.jsx(F,{children:e.jsx(z,{placeholder:"123 Main St",...t,value:t.value||"","data-testid":"input-address"})}),e.jsx(_,{})]})}),e.jsx(I,{control:f.control,name:"city",render:({field:t})=>e.jsxs($,{children:[e.jsx(R,{children:"City"}),e.jsx(F,{children:e.jsx(z,{placeholder:"Austin",...t,value:t.value||"","data-testid":"input-city"})}),e.jsx(_,{})]})}),e.jsx(I,{control:f.control,name:"state",render:({field:t})=>e.jsxs($,{children:[e.jsx(R,{children:"State"}),e.jsx(F,{children:e.jsx(z,{placeholder:"TX",...t,value:t.value||"","data-testid":"input-state"})}),e.jsx(_,{})]})})]}),e.jsx(I,{control:f.control,name:"description",render:({field:t})=>e.jsxs($,{children:[e.jsx(R,{children:"Description"}),e.jsx(F,{children:e.jsx(Ft,{placeholder:"Brief description of the project scope...",className:"min-h-[80px]",...t,value:t.value||"","data-testid":"input-description"})}),e.jsx(_,{})]})}),e.jsx(ge,{className:"my-2"}),e.jsxs("div",{className:"space-y-1",children:[e.jsx(le,{className:"text-sm font-medium",children:"Portfolio Rollup"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Optional. Used by the Portfolio Rollup dashboard to group projects by Program, Division, and Trade."})]}),e.jsxs("div",{className:"grid grid-cols-3 gap-4",children:[e.jsx(I,{control:f.control,name:"programId",render:({field:t})=>e.jsxs($,{children:[e.jsx(R,{children:"Program"}),e.jsx(F,{children:e.jsx(z,{placeholder:"e.g. Highway 87 Corridor",...t,value:t.value||"","data-testid":"input-program-id"})}),e.jsx(_,{})]})}),e.jsx(I,{control:f.control,name:"divisionId",render:({field:t})=>e.jsxs($,{children:[e.jsx(R,{children:"Division"}),e.jsx(F,{children:e.jsx(z,{placeholder:"e.g. Northern Region",...t,value:t.value||"","data-testid":"input-division-id"})}),e.jsx(_,{})]})}),e.jsx(I,{control:f.control,name:"primaryTradeType",render:({field:t})=>e.jsxs($,{children:[e.jsx(R,{children:"Primary Trade"}),e.jsxs(ne,{value:t.value||"__none__",onValueChange:d=>t.onChange(d==="__none__"?void 0:d),children:[e.jsx(F,{children:e.jsx(re,{"data-testid":"select-primary-trade-type",children:e.jsx(ie,{placeholder:"Select trade..."})})}),e.jsxs(oe,{children:[e.jsx(U,{value:"__none__",children:"None"}),Cs.enumValues.map(d=>e.jsx(U,{value:d,children:d.replace(/_/g," ")},d))]})]}),e.jsx(_,{})]})})]}),e.jsxs(_t,{children:[e.jsx(V,{type:"button",variant:"outline",onClick:()=>Le(!1),"data-testid":"button-cancel",children:"Cancel"}),e.jsx(V,{type:"submit",disabled:k.isPending,"data-testid":"button-create-project",children:k.isPending?"Creating...":"Create Project"})]})]})})]})}),e.jsx(hs,{open:G,onOpenChange:A,children:e.jsxs(xs,{"data-testid":"dialog-delete-project",children:[e.jsxs(ps,{children:[e.jsxs(js,{className:"flex items-center gap-2",children:[e.jsx(Se,{className:"w-5 h-5 text-destructive"}),"Delete Project"]}),e.jsxs(gs,{children:["Are you sure you want to delete project"," ",e.jsx("strong",{children:j==null?void 0:j.code})," (",j==null?void 0:j.name,")?",e.jsx("br",{}),e.jsx("br",{}),"This action cannot be undone. All associated data including estimates, change orders, time entries, procurement items, and documents will also be deleted."]})]}),e.jsxs(fs,{children:[e.jsx(vs,{onClick:()=>M(null),"data-testid":"button-cancel-delete",children:"Cancel"}),e.jsx(bs,{onClick:mt,className:"bg-destructive hover:bg-destructive/90","data-testid":"button-confirm-delete",children:D.isPending?"Deleting...":"Delete Project"})]})]})})]})}export{ta 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.