1import{u as Te,r as d,j as e,y as Pe,a4 as $e,a5 as Ie,a6 as Re,V as O,a8 as qe,B as k,o as P,R as Fe,cl as Ee,a9 as He,I as he,S as Q,i as U,k as V,l as D,m as N,W as G,H as We,J as ze,K as I,N as w,O as Be,Q as j,C as pe,z as X,A as Y,G as Z,$ as Je,X as Ke,d as Oe,w as m,bu as Qe,Y as Ue,a2 as Ve,a3 as De,v as g}from"./index-CERo9Lrd.js";import{J as Ge}from"./JobDetailModal-ECLFeOX6.js";import"./JobDetailActions-DVYo97Ez.js";const je=(C,T)=>`${(C||"").trim().toLowerCase()}|${(T||"").trim().toLowerCase()}`,L=25,Xe=()=>{var ue;const{user:C}=Te(),[T,ee]=d.useState(!0),[v,R]=d.useState([]),[se,q]=d.useState(new Set),[be,ge]=d.useState(new Set),[fe,F]=d.useState(new Set),[ae,te]=d.useState(null),[_,ne]=d.useState(null),[S,$]=d.useState(1),[re,ie]=d.useState(!1),[ye,le]=d.useState(!1),[oe,ce]=d.useState(!1),[E,we]=d.useState("all"),[H,_e]=d.useState("all"),[W,Ne]=d.useState("all"),[z,ve]=d.useState(""),[B,Se]=d.useState(""),J=async()=>{ee(!0),le(!1);try{const{data:s,error:n}=await g.rpc("get_predicted_winners",{_limit:3e3,_category:E==="all"?null:E,_country:H==="all"?null:H,_work_mode:W==="all"?null:W,_min_salary:z?Number(z):null});if(n){console.error("[PredictedWinners] rpc error",n),m.error("Failed to load predicted winners"),R([]);return}const r=s||[],h=new Map;for(const a of r){const l=je(a.company,a.title),o=h.get(l),i=[a.city,a.state,a.job_country].filter(Boolean).join(", ");o?(o.locationCount=(o.locationCount||1)+1,i&&!o.locations.includes(i)&&o.locations.push(i),o.groupMemberIds.push(a.job_id)):h.set(l,{...a,locationCount:1,locations:i?[i]:[],groupMemberIds:[a.job_id]})}const x=Array.from(h.values()),u=x.flatMap(a=>a.groupMemberIds||[a.job_id]),c=new Map;for(let a=0;a<u.length;a+=500){const l=u.slice(a,a+500),{data:o}=await g.from("job_metrics").select("job_id, cpa").in("job_id",l).not("cpa","is",null);for(const i of o||[])i.cpa!=null&&c.set(i.job_id,Number(i.cpa))}for(const a of x){let l=null;for(const o of a.groupMemberIds||[a.job_id]){const i=c.get(o);i!=null&&(l==null||i>l)&&(l=i)}a.cpa=l}R(x),$(1);const b=x.map(a=>a.job_id),y=new Set;for(let a=0;a<b.length;a+=200){const l=b.slice(a,a+200),{data:o}=await g.from("published_jobs").select("job_id").in("job_id",l);for(const i of o||[])y.add(i.job_id)}q(y);const t=new Set;for(let a=0;a<b.length;a+=200){const l=b.slice(a,a+200),[{data:o},{data:i}]=await Promise.all([g.from("linkedin_xml_queue").select("job_id").in("job_id",l).eq("status","pending"),g.from("linkedin_xml_formatted_jobs").select("job_id").in("job_id",l)]);for(const M of o||[])t.add(M.job_id);for(const M of i||[])t.add(M.job_id)}F(t);const p=new Set,A=[];for(const a of x){const l=(a.company||"").trim(),o=(a.title||"").trim();if(!l||!o)continue;const i=`${l.toLowerCase()}|${o.toLowerCase()}`;p.has(i)||(p.add(i),A.push({company:l,title:o}))}const xe=new Set;if(A.length>0)for(let a=0;a<A.length;a+=2e3){const l=A.slice(a,a+2e3),{data:o,error:i}=await g.rpc("get_published_sibling_keys",{_pairs:l});if(i){console.error("[PredictedWinners] sibling rpc error",i);continue}for(const M of o||[])xe.add(`${M.company_lower}|${M.title_lower}`)}ge(xe)}finally{ee(!1)}};d.useEffect(()=>{J()},[]);const f=d.useMemo(()=>{const s=B.trim().toLowerCase();return s?v.filter(n=>(n.title||"").toLowerCase().includes(s)||(n.company||"").toLowerCase().includes(s)):v},[v,B]),de=async s=>{if(!C){m.error("You must be logged in");return}const{error:n}=await g.from("published_jobs").insert({job_id:s,user_id:C.id});if(n){n.code==="23505"?(m.message("Already published"),q(r=>new Set([...r,s]))):(console.error(n),m.error("Failed to publish"));return}m.success("Added to published jobs"),q(r=>new Set([...r,s]))},ke=async s=>{if(!C){m.error("You must be logged in");return}te(s);try{const{error:n}=await g.from("linkedin_xml_queue").insert({job_id:s,added_by:C.id,status:"pending"});if(n){n.code==="23505"?(m.message("Already in queue"),F(r=>new Set([...r,s]))):(console.error("[PredictedWinners] queue error",n),m.error("Failed to add to queue"));return}F(r=>new Set([...r,s])),m.success("Added to XML queue")}finally{te(null)}},Ce=async()=>{if(f.length!==0){ie(!0);try{const s=f.slice(0,200).map(t=>({job_id:t.job_id,title:t.title,company:t.company,category:t.category,work_mode:t.work_mode,seniority_level:t.seniority_level,country:t.job_country,salary_min:t.salary_min,score:t.score})),n=["Top categories that convert: Technology, Engineering, Healthcare.","Strong markets: US, UK, Germany, France.","Penalise staffing-agency-style listings and vague titles."].join(" "),{data:r,error:h}=await g.functions.invoke("rerank-predicted-winners",{body:{candidates:s,top_n:50,profile:n}});if(h){console.error(h),m.error("AI re-rank failed");return}const x=(r==null?void 0:r.ranked)||[];if(x.length===0){m.message("AI returned no picks");return}const u=new Map(x.map(t=>[t.job_id,t.rationale])),c=new Map(x.map((t,p)=>[t.job_id,p])),b=[...v].filter(t=>c.has(t.job_id)).map(t=>({...t,rationale:u.get(t.job_id)})).sort((t,p)=>(c.get(t.job_id)??0)-(c.get(p.job_id)??0)),y=v.filter(t=>!c.has(t.job_id));R([...b,...y]),le(!0),$(1),m.success(`AI ranked top ${x.length} picks${r!=null&&r.cached?" (cached)":""}`)}finally{ie(!1)}}},Ae=async()=>{ce(!0);try{const{error:s}=await g.rpc("refresh_predicted_winner_scores");s?(console.error(s),m.error("Refresh failed")):(m.success("Scores refreshed"),await J())}finally{ce(!1)}},Me=s=>
1{const n=[s.city,s.job_country].filter(Boolean);return n.length?n.join(", "):"-"},Le=s=>{if(!s.salary_min&&!s.salary_max)return"-";const n=s.salary_currency||"$",r=h=>`${n}${Math.round(h/1e3)}k`;return s.salary_min&&s.salary_max?`${r(s.salary_min)}-${r(s.salary_max)}`:r(s.salary_min||s.salary_max)},K=Math.max(1,Math.ceil(f.length/L)),me=f.slice((S-1)*L,S*L);return e.jsxs(Pe,{delayDuration:150,children:[e.jsxs($e,{children:[e.jsx(Ie,{children:e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsxs(Re,{className:"flex items-center gap-2",children:[e.jsx(O,{className:"h-5 w-5 text-primary"}),"Predicted Winners"]}),e.jsx(qe,{children:"Active Appcast jobs ranked by likelihood to convert, based on historical Haystack performance across company, category, seniority, country and salary band. Optionally re-rank the top 200 with AI."})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs(k,{variant:"outline",size:"sm",onClick:Ae,disabled:oe,title:"Recompute scores from latest conversions",children:[oe?e.jsx(P,{className:"h-4 w-4 animate-spin"}):e.jsx(Fe,{className:"h-4 w-4"}),e.jsx("span",{className:"ml-2 hidden sm:inline",children:"Recompute"})]}),e.jsxs(k,{size:"sm",onClick:Ce,disabled:re||f.length===0,children:[re?e.jsx(P,{className:"h-4 w-4 animate-spin"}):e.jsx(Ee,{className:"h-4 w-4"}),e.jsx("span",{className:"ml-2",children:"AI re-rank top 50"})]})]})]})}),e.jsxs(He,{className:"space-y-4",children:[e.jsxs("div",{className:"grid gap-2 sm:grid-cols-2 lg:grid-cols-5",children:[e.jsx(he,{placeholder:"Search title or company...",value:B,onChange:s=>Se(s.target.value)}),e.jsxs(Q,{value:E,onValueChange:we,children:[e.jsx(U,{children:e.jsx(V,{placeholder:"Category"})}),e.jsxs(D,{children:[e.jsx(N,{value:"all",children:"All categories"}),["Technology","Engineering","Healthcare","Finance","Sales","Marketing","Operations","Education","Customer Service"].map(s=>e.jsx(N,{value:s,children:s},s))]})]}),e.jsxs(Q,{value:H,onValueChange:_e,children:[e.jsx(U,{children:e.jsx(V,{placeholder:"Country"})}),e.jsxs(D,{children:[e.jsx(N,{value:"all",children:"All countries"}),["United States","United Kingdom","Germany","France","Spain","Canada"].map(s=>e.jsx(N,{value:s,children:s},s))]})]}),e.jsxs(Q,{value:W,onValueChange:Ne,children:[e.jsx(U,{children:e.jsx(V,{placeholder:"Work mode"})}),e.jsxs(D,{children:[e.jsx(N,{value:"all",children:"Any work mode"}),e.jsx(N,{value:"remote",children:"Remote"}),e.jsx(N,{value:"hybrid",children:"Hybrid"}),e.jsx(N,{value:"onsite",children:"On-site"})]})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(he,{type:"number",placeholder:"Min salary",value:z,onChange:s=>ve(s.target.value)}),e.jsx(k,{variant:"secondary",onClick:J,disabled:T,children:T?e.jsx(P,{className:"h-4 w-4 animate-spin"}):"Apply"})]})]}),e.jsxs("div",{className:"flex items-center gap-2 text-xs text-muted-foreground",children:[e.jsxs(G,{variant:"secondary",children:[f.length," candidates"]}),ye&&e.jsxs(G,{variant:"outline",className:"border-primary/40 text-primary",children:[e.jsx(O,{className:"h-3 w-3 mr-1"})," AI ranked"]}),((ue=v[0])==null?void 0:ue.refreshed_at)&&e.jsxs("span",{children:["Scores from ",new Date(v[0].refreshed_at).toLocaleString()]})]}),e.jsx("div",{className:"rounded-md border overflow-x-auto",children:e.jsxs(We,{children:[e.jsx(ze,{children:e.jsxs(I,{children:[e.jsx(w,{className:"w-[100px]",children:"Status"}),e.jsx(w,{className:"w-[80px]",children:"Score"}),e.jsx(w,{children:"Title"}),e.jsx(w,{children:"Company"}),e.jsx(w,{children:"Location"}),e.jsx(w,{children:"Category"}),e.jsx(w,{children:"Salary"}),e.jsx(w,{className:"w-[70px] text-right",children:"CPA"}),e.jsx(w,{className:"w-[180px] text-right",children:"Action"})]})}),e.jsx(Be,{children:T?e.jsx(I,{children:e.jsx(j,{colSpan:9,className:"text-center py-8",children:e.jsx(P,{className:"h-5 w-5 animate-spin text-primary inline-block"})})}):me.length===0?e.jsx(I,{children:e.jsx(j,{colSpan:9,className:"text-center py-8 text-muted-foreground text-sm",children:"No predicted winners match your filters."})}):me.map(s=>{const n=se.has(s.job_id),r=!n&&be.has(je(s.company,s.title)),h=Math.max(0,Math.min(100,Math.round(s.score))),x=(s.locationCount||1)-1;
1return e.jsxs(I,{className:`cursor-pointer hover:bg-muted/50 ${n?"bg-emerald-500/[0.04]":r?"bg-amber-500/[0.04]":""}`,onClick:()=>ne(s),children:[e.jsx(j,{children:n?e.jsxs("span",{className:"inline-flex items-center gap-1 h-5 px-1.5 rounded-md text-[10px] font-medium border border-emerald-500/40 text-emerald-700 dark:text-emerald-400 bg-emerald-500/5 whitespace-nowrap",children:[e.jsx(pe,{className:"h-2.5 w-2.5 shrink-0"})," Live"]}):r?e.jsxs(X,{children:[e.jsx(Y,{asChild:!0,children:e.jsxs("span",{className:"inline-flex items-center gap-1 h-5 px-1.5 rounded-md text-[10px] font-medium border border-amber-500/40 text-amber-700 dark:text-amber-400 bg-amber-500/5 whitespace-nowrap",children:[e.jsx(pe,{className:"h-2.5 w-2.5 shrink-0"})," Sibling"]})}),e.jsx(Z,{className:"text-xs max-w-xs",children:"A job with the same title and company is already published. This specific listing is not."})]}):e.jsxs("span",{className:"inline-flex items-center gap-1 h-5 px-1.5 rounded-md text-[10px] font-medium border border-muted-foreground/30 text-muted-foreground whitespace-nowrap",children:[e.jsx(Je,{className:"h-2.5 w-2.5 shrink-0"})," Not live"]})}),e.jsx(j,{children:e.jsxs(X,{children:[e.jsx(Y,{asChild:!0,children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:"h-1.5 w-12 rounded-full bg-muted overflow-hidden",children:e.jsx("div",{className:"h-full bg-primary",style:{width:`${h}%`}})}),e.jsx("span",{className:"text-xs tabular-nums",children:h})]})}),e.jsx(Z,{className:"max-w-sm text-xs",children:s.rationale?e.jsxs("div",{className:"space-y-1",children:[e.jsxs("div",{className:"font-medium flex items-center gap-1",children:[e.jsx(O,{className:"h-3 w-3"})," AI rationale"]}),e.jsx("div",{children:s.rationale})]}):s.score_breakdown?(()=>{const u=s.score_breakdown||{},c=u.company||{},b=Number(u.global_rate||0),y=c.rate!=null?Number(c.rate):null,t=A=>`${(A*100).toFixed(2)}%`,p=y!=null&&b>0?y/b:null;return e.jsxs("div",{className:"space-y-2",children:[c.jobs!=null&&e.jsxs("div",{className:`rounded border px-2 py-1.5 ${c.gated?"border-muted-foreground/30":"border-primary/40 bg-primary/5"}`,children:[e.jsxs("div",{className:"font-medium",children:["Company signal ",c.gated?"(gated)":""]}),e.jsxs("div",{className:"text-muted-foreground",children:[Number(c.jobs)," jobs, ",Number(c.conv||0)," conv",y!=null&&e.jsxs(e.Fragment,{children:[" - rate ",t(y)," vs global ",t(b)]})]}),!c.gated&&p!=null&&e.jsx("div",{className:"text-primary",children:p>=1?`${p.toFixed(2)}x lift`:`${p.toFixed(2)}x (below avg)`}),c.gated&&e.jsx("div",{className:"text-muted-foreground italic",children:"Too few historical jobs (need 5+) - company boost not applied."})]}),e.jsx("pre",{className:"text-[10px] whitespace-pre-wrap text-muted-foreground",children:JSON.stringify(u,null,2)})]})})():e.jsx("span",{children:"No breakdown"})})]})}),e.jsx(j,{className:"font-medium text-sm max-w-[280px] truncate",children:Ke(s.title)}),e.jsx(j,{className:"text-sm max-w-[180px] truncate text-muted-foreground",children:Oe(s.company||"")||"-"}),e.jsx(j,{className:"text-xs max-w-[200px] text-muted-foreground",children:e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:"truncate",children:Me(s)}),x>0&&e.jsxs(X,{children:[e.jsx(Y,{asChild:!0,children:e.jsxs(G,{variant:"secondary",className:"h-4 px-1 text-[10px] font-medium shrink-0",children:["+",x]})}),e.jsxs(Z,{className:"text-xs max-w-xs",children:[e.jsxs("div",{className:"font-medium mb-1",children:[s.locationCount||1," locations"]}),e.jsxs("div",{className:"space-y-0.5",children:[(s.locations||[]).slice(0,12).map((u,c)=>e.jsx("div",{children:u},c)),(s.locations||[]).length>12&&e.jsxs("div",{className:"text-muted-foreground",children:["+",(s.locations||[]).length-12," more"]})]})]})]})]})}),e.jsx(j,{className:"text-xs text-muted-foreground",children:s.category||"-"}),e.jsx(j,{className:"text-xs tabular-nums text-muted-foreground",children:Le(s)}),e.jsx(j,{className:"text-xs tabular-nums text-right",children:s.cpa!=null?e.jsxs("span",{className:"font-medium text-emerald-700 dark:text-emerald-400",children:["$",Number(s.cpa).toFixed(2)]}):e.jsx("span",{className:"text-muted-foreground",children:"-"})}),e.jsx(j,{className:"text-right",onClick:u=>u.stopPropagation(),children:e.jsxs("div",{className:"flex items-center justify-end gap-1",children:[s.apply_url&&e.jsxs(e.Fragment,{children:[e.jsx("button",{type:"button",onClick:async()=>{try{await navigator.clipboard.writeText(s.apply_url),m.success("Apply URL copied")}catch{m.error("Failed to copy")}},className:"text-muted-foreground hover:text-primary inline-flex",title:"Copy apply
1URL",children:e.jsx(Qe,{className:"h-3.5 w-3.5"})}),e.jsx("a",{href:s.apply_url,target:"_blank",rel:"noopener noreferrer",className:"text-muted-foreground hover:text-primary inline-flex",title:"Open apply URL",children:e.jsx(Ue,{className:"h-3.5 w-3.5"})})]}),(()=>{const u=fe.has(s.job_id);return e.jsx(k,{size:"sm",variant:"outline",disabled:u||ae===s.job_id,onClick:()=>ke(s.job_id),title:"Add to LinkedIn XML queue",children:ae===s.job_id?e.jsx(P,{className:"h-3 w-3 animate-spin"}):u?"Queued":"Queue"})})(),e.jsx(k,{size:"sm",variant:n||r?"outline":"default",disabled:n||r,onClick:()=>de(s.job_id),title:r?"A sibling listing is already published":void 0,children:n?"Live":r?"Sibling live":"Publish"})]})})]},s.job_id)})})]})}),f.length>L&&e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("span",{className:"text-xs text-muted-foreground tabular-nums",children:[(S-1)*L+1,"-",Math.min(S*L,f.length)," of ",f.length]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(k,{variant:"outline",size:"sm",onClick:()=>$(s=>Math.max(1,s-1)),disabled:S===1,children:e.jsx(Ve,{className:"h-4 w-4"})}),e.jsxs("span",{className:"text-xs tabular-nums px-2",children:[S," / ",K]}),e.jsx(k,{variant:"outline",size:"sm",onClick:()=>$(s=>Math.min(K,s+1)),disabled:S===K,children:e.jsx(De,{className:"h-4 w-4"})})]})]})]})]}),e.jsx(Ge,{job:_?{..._,id:_.job_id}:null,open:!!_,onOpenChange:s=>!s&&ne(null),isPublished:_?se.has(_.job_id):!1,onPublish:_?()=>de(_.job_id):void 0})]})},ss=()=>e.jsx("div",{className:"space-y-6",children:e.jsx(Xe,{})});export{ss 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.