1import{ai as H,o as A,A as q,al as C,a4 as k,U as j,an as F,a5 as P,j as e,C as h,$ as X,T as l,D as _,G as d,L as Y,aM as V,aR as J,E as f,W as I,F as K,ao as O,K as Z,X as T,B as ee,au as se,aw as D,av as R,I as B,bs as g,S as te,H as ie,ab as ae}from"./index-dE8a1mPK.js";import{E as M}from"./ErrorState-gVNyx0--.js";import{E as oe}from"./EmptyState-BpgfYYCq.js";import{S as re}from"./SimpleGrid-DkEuk0DW.js";import{I as U}from"./IconArrowRight-Ajq43paw.js";import{I as ne}from"./IconTrash-DIXYcrq7.js";import{S as le}from"./Select-DebRlW67.js";import{I as de}from"./IconPlus-B47PY1MC.js";import{I as ce}from"./IconExternalLink-DcQXcLz7.js";import{I as W,a as N}from"./IconTrendingUp-BCwZs3xF.js";import"./IconCopy-B63sUmw8.js";import"./Code-YtMEZkZ5.js";import"./OptionsDropdown-wonErrz5.js";import"./CheckIcon-DkMc45y2.js";function Le(){const t=H(),[i,w]=A.useState(""),[p,y]=A.useState(null),{data:o,isLoading:c,error:u}=q({queryKey:["competitors"],queryFn:()=>j.listCompetitors()}),a=q({queryKey:["lists"],queryFn:()=>j.listLists()}),v=A.useMemo(()=>{var s;return(((s=a.data)==null?void 0:s.lists)||[]).filter(r=>r.kind!=="smart")},[a.data]),L=C({mutationFn:({id:s,patch:r})=>j.updateCompetitor(s,r),onSuccess:()=>t.invalidateQueries({queryKey:["competitors"]}),onError:s=>k(s)}),b=C({mutationFn:s=>j.pipeCompetitorLatest(s),onSuccess:s=>{s.reason==="no-deltas-yet"?F("No deltas yet â first snapshot is the baseline; the next one produces gained handles."):s.reason==="no-gained-followers"?F("No new followers in the latest delta."):(P(`Piped ${s.added??0} new handles into the list (${s.total} total).`),t.invalidateQueries({queryKey:["lists"]}))},onError:s=>k(s)}),$=C({mutationFn:()=>j.addCompetitor({handle:i.trim().replace(/^@/,"")}),onSuccess:s=>{var r,x;P((r=s.watch)!=null&&r.reused?`Already watching @${s.watch.handle}`:`Watching @${(x=s.watch)==null?void 0:x.handle} â first snapshot runs on the next worker tick (~1 min)`),w(""),t.invalidateQueries({queryKey:["competitors"]})},onError:s=>k(s)}),G=C({mutationFn:s=>j.removeCompetitor(s),onSuccess:()=>t.invalidateQueries({queryKey:["competitors"]}),onError:s=>k(s)}),E=C({mutationFn:s=>
1j.refreshCompetitor(s),onSuccess:(s,r)=>{var x,S;s.skipped?F(`Skipped: ${s.skipped}`):P(`Snapshot done â ${s.count??0} followers (+${((x=s.gained)==null?void 0:x.length)??0} / â${((S=s.lost)==null?void 0:S.length)??0})`),t.invalidateQueries({queryKey:["competitors"]}),t.invalidateQueries({queryKey:["competitor-deltas",r]})},onError:s=>k(s)}),z=(o==null?void 0:o.watches)||[],m=A.useMemo(()=>z.find(s=>s.id===p)||z[0]||null,[z,p]);return e.jsxs(h,{gap:"md",children:[e.jsxs("div",{children:[e.jsx(X,{order:2,children:"Competitor watch"}),e.jsx(l,{c:"dimmed",size:"sm",mt:2,children:"Track who's following any X account â snapshots run daily and surface new + lost followers. Useful for finding warm leads (people who just followed a competitor) and watching churn (people who unfollowed them)."})]}),e.jsx(_,{withBorder:!0,children:e.jsxs(d,{gap:"xs",align:"flex-end",wrap:"wrap",children:[e.jsx(Y,{label:"Add competitor",placeholder:"@handle",value:i,onChange:s=>w(s.currentTarget.value),onKeyDown:s=>{s.key==="Enter"&&i.trim()&&$.mutate()},style:{minWidth:280}}),e.jsx(ue,{watchCount:z.length,disabled:!i.trim(),loading:$.isPending,onClick:()=>$.mutate()})]})}),c&&e.jsx(V,{}),u&&e.jsx(M,{error:u,onRetry:()=>t.invalidateQueries({queryKey:["competitors"]})}),!c&&!u&&z.length===0&&e.jsx(oe,{icon:e.jsx(J,{size:32,stroke:1.5}),title:"No competitors watched yet",description:"Add an X handle above to start tracking their follower changes. Daily snapshots, with new and lost followers surfaced in a drilldown so you can act on them."}),z.length>0&&e.jsxs(re,{cols:{base:1,md:3},spacing:"md",children:[e.jsx(h,{gap:"xs",style:{gridColumn:"span 1"},children:z.map(s=>{var r,x,S;return e.jsxs(_,{withBorder:!0,p:"sm",onClick:()=>y(s.id),style:{cursor:"pointer",borderColor:(m==null?void 0:m.id)===s.id?"var(--mantine-color-text)":void 0,borderWidth:(m==null?void 0:m.id)===s.id?2:void 0},children:[e.jsxs(d,{justify:"space-between",wrap:"nowrap",children:[e.jsxs(h,{gap:2,style:{minWidth:0,flex:1},children:[e.jsxs(l,{fw:600,truncate:!0,children:["@",s.handle]}),e.jsxs(d,{gap:"xs",wrap:"wrap",children:[e.jsxs(f,{size:"xs",variant:"light",children:[((x=(r=s.lastFollowerCount)==null?void 0:r.toLocaleString)==null?void 0:x.call(r))||"â"," followers"]}),e.jsx(l,{size:"xs",c:"dimmed",children:s.lastRunAt?`last ${new Date(s.lastRunAt).toLocaleString()}`:"awaiting first snapshot"})]}),s.lastError&&e.jsx(l,{size:"xs",c:"red",children:s.lastError}),s.autoAddToListId&&e.jsxs(f,{size:"xs",variant:"light",color:"dark",leftSection:e.jsx(U,{size:10}),children:["piping to ",((S=v.find(n=>n.id===s.autoAddToListId))==null?void 0:S.name)||"list"]})]}),e.jsxs(h,{gap:4,children:[e.jsx(I,{label:"Refresh now",children:e.jsx(K,{size:"sm",variant:"default",onClick:n=>{n.stopPropagation(),E.mutate(s.id)},loading:E.isPending&&E.variables===s.id,children:e.jsx(O,{size:12})})}),e.jsx(I,{label:"Remove",children:e.jsx(K,{size:"sm",variant:"subtle",color:"red",onClick:n=>{n.stopPropagation(),G.mutate(s.id)},children:e.jsx(ne,{size:12})})})]})]}),e.jsx(Z,{my:"xs"}),e.jsx(h,{gap:4,onClick:n=>n.stopPropagation(),children:e.jsxs(d,{gap:6,align:"flex-end",children:[e.jsx(le,{size:"xs",placeholder:"Pipe new followers toâ¦",data:[{value:"__none__",label:"No pipe (just snapshot)"},...v.map(n=>({value:n.id,label:n.name}))],value:s.autoAddToListId||"__none__",onChange:n=>L.mutate({id:s.id,patch:{autoAddToListId:n==="__none__"?null:n}}),style:{flex:1},allowDeselect:!1,searchable:!0}),s.autoAddToListId&&e.jsx(I,{label:"Add today's gained followers to the list right now (instead of waiting for tomorrow's snapshot)",children:e.jsx(T,{size:"xs",variant:"default",onClick:()=>b.mutate(s.id),loading:b.isPending&&b.variables===s.id,children:"Pipe now"})})]})})]},s.id)})}),e.jsx(ee,{style:{gridColumn:"span 2"},children:m?e.jsx(he,{watch:m}):null})]})]})}function he({watch:t}){var c,u;const{data:i,isLoading:w,error:p}=q({queryKey:["competitor-deltas",t.id],queryFn:()=>j.competitorDeltas(t.id,14)}),y=(i==null?void 0:i.deltas)||[],o=y[0];return e.jsxs(_,{withBorder:!0,p:"md",children:[e.jsxs(d,{justify:"space-between",align:"flex-start",mb:"md",children:[e.jsxs(h,{gap:2,children:[e.jsxs(B,{href:`https://x.com/${t.handle}`,target:"_blank",rel:"noreferrer",fw:700,size:"lg",children:["@",t.handle," ",e.jsx(ce,{size:12,style:{verticalAlign:-1}})]}),e.jsxs(l,{size:"xs",c:"dimmed",children:["Watching since ",new Date(t.addedAt).toLocaleDateString()]})]}),o&&e.jsxs(f,{variant:"light",color:o.delta>=0?"green":"red",leftSection:o.delta>=0?e.jsx(W,{size:12}):e.jsx(N,{size:12}),children:[o.delta>=0?"+":"",o.delta," vs ",o.vsSnapshotDate||"previous"]})]}),w&&e.jsx(l,{size:"sm",c:"dimmed",children:"Loading deltasâ¦"}),p&&e.jsx(M,{error:p}),!w&&!p&&!y.length&&e.jsx(l,{size:"sm",c:"dimmed",children:"No deltas yet â the first snapshot is the baseline;
1 the second one (~24h later, or hit Refresh now twice) produces a diff."}),o&&e.jsxs(g,{defaultValue:"gained",mt:"md",children:[e.jsxs(g.List,{children:[e.jsxs(g.Tab,{value:"gained",leftSection:e.jsx(W,{size:12}),children:["New followers (",((c=o.gained)==null?void 0:c.length)||0,")"]}),e.jsxs(g.Tab,{value:"lost",leftSection:e.jsx(N,{size:12}),children:["Lost followers (",((u=o.lost)==null?void 0:u.length)||0,")"]}),e.jsx(g.Tab,{value:"history",children:"14-day history"})]}),e.jsx(g.Panel,{value:"gained",pt:"sm",children:e.jsx(Q,{followers:o.gained||[]})}),e.jsx(g.Panel,{value:"lost",pt:"sm",children:e.jsx(Q,{followers:o.lost||[]})}),e.jsx(g.Panel,{value:"history",pt:"sm",children:e.jsx(h,{gap:"xs",children:y.map(a=>{var v,L,b;return e.jsxs(d,{justify:"space-between",wrap:"wrap",gap:"xs",children:[e.jsxs(d,{gap:"xs",children:[e.jsx(l,{size:"sm",children:a.date}),((v=a.pipedToList)==null?void 0:v.added)>0&&e.jsxs(f,{size:"xs",variant:"outline",color:"dark",leftSection:e.jsx(U,{size:10}),children:["piped ",a.pipedToList.added]})]}),e.jsxs(d,{gap:"xs",children:[e.jsxs(f,{size:"xs",color:"green",variant:"light",children:["+",((L=a.gained)==null?void 0:L.length)||0]}),e.jsxs(f,{size:"xs",color:"red",variant:"light",children:["â",((b=a.lost)==null?void 0:b.length)||0]}),e.jsxs(f,{size:"xs",color:a.delta>=0?"green":"red",variant:a.delta===0?"outline":"filled",children:[a.delta>=0?"+":"",a.delta]})]})]},a.date)})})})]})]})}function Q({followers:t}){return t.length?e.jsx(te,{h:420,children:e.jsx(h,{gap:"xs",children:t.map(i=>e.jsxs(d,{wrap:"nowrap",gap:"xs",children:[e.jsx(ie,{src:i.avatar,radius:"xl",size:"sm",children:(i.handle||"?").slice(0,1).toUpperCase()}),e.jsxs(h,{gap:0,style:{minWidth:0,flex:1},children:[e.jsxs(d,{gap:4,wrap:"nowrap",children:[e.jsxs(B,{href:`https://x.com/${i.handle}`,target:"_blank",rel:"noreferrer",fw:600,size:"sm",children:["@",i.handle]}),i.name&&e.jsx(l,{size:"xs",c:"dimmed",truncate:!0,maw:180,children:i.name}),i.verified&&e.jsx(ae,{size:11,color:"var(--mantine-color-blue-6)"}),typeof i.followers=="number"&&e.jsx(f,{size:"xs",variant:"outline",color:"gray",children:pe(i.followers)})]}),i.bio&&e.jsx(l,{size:"xs",c:"dimmed",truncate:!0,children:i.bio})]})]},i.id||i.handle))})}):e.jsx(l,{size:"sm",c:"dimmed",children:"None on this date."})}function pe(t){return t==null?"":t>=1e6?`${(t/1e6).toFixed(1)}M`:t>=1e3?`${(t/1e3).toFixed(1)}K`:String(t)}function ue({watchCount:t,disabled:i,loading:w,onClick:p}){const{hasFeature:y,capFor:o,planLabel:c}=se(),u=y("competitorWatches"),a=o("competitorWatches"),v=a!==null&&t>=a;return u?v?e.jsx(I,{label:`Your ${c} plan caps competitor watches at ${a}. Upgrade for more.`,withArrow:!0,children:e.jsxs(T,{onClick:()=>R({reason:`Your ${c} plan caps competitor watches at ${a}.`,code:"plan-cap"}),variant:"light",color:"dark",leftSection:e.jsx(D,{size:14}),children:[t,"/",a," â upgrade"]})}):e.jsxs(T,{leftSection:e.jsx(de,{size:14}),onClick:p,loading:w,disabled:i,children:["Add",a!==null?` (${t}/${a})`:""]}):e.jsx(I,{label:`Your ${c} plan doesn't include competitor watches. Upgrade to Starter.`,withArrow:!0,children:e.jsx(T,{onClick:()=>R({reason:"Competitor watches are a paid feature.",code:"plan-gate"}),variant:"light",color:"dark",leftSection:e.jsx(D,{size:14}),children:"Upgrade to unlock"})})}export{Le 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.