1import{r as b,j as e}from"./react-vendor-DUhHROXo.js";import{A as z}from"./AdminLayout-4AAuHeAU.js";import{C as _,a as C,b as V,c as $,d as F}from"./card-9IoFUltb.js";import{o as p,D as G,aN as J,q as K,s as Q,t as W,aO as X,aP as Y}from"./index-BLtzf0SR.js";import{I as y}from"./input-RFokm5kN.js";import{L as d}from"./label-B2yiss_Q.js";import{B as S}from"./badge-BsE4KYIf.js";import{T as Z}from"./textarea-Da4-oaTC.js";import{S as ee}from"./switch-DacJ_cba.js";import{S as k,a as D,b as T,c as A,d as m}from"./select-CMAo_7oa.js";import{s as h}from"./client-DTel1CZI.js";import{u as g}from"./index-Cx0UdoxP.js";import{L as se}from"./router-vendor-Dz9PdDzH.js";import{l as q}from"./subscriberAudit-1DeUJZBb.js";import{A as re}from"./arrow-left-CRb8P6iH.js";import{P as ie}from"./plus-Db1qFqHY.js";import{U as te}from"./users-CIwSfVhi.js";import{R as ae}from"./refresh-cw-BBiwQZvS.js";import{T as ne}from"./trash-2-cCh6Q5cl.js";import{f as ce}from"./format-DGzj7MEM.js";import"./NavLink-CsyG-eHO.js";import"./scroll-area-BdyOmc9o.js";import"./index-BdQq_4o_.js";import"./collapsible-BAD8kbtc.js";import"./index-CMI-ZfmW.js";import"./globe-CQ83QW2m.js";import"./activity-CwFToTs3.js";import"./list-todo-BR3jv1RJ.js";import"./calendar-BDETTnfZ.js";import"./users-round-CCw5yxW7.js";import"./radio-BQgeDg5T.js";import"./clapperboard-BvstouST.js";import"./clipboard-list-CQJ-vJ2y.js";import"./image-arBWrt3y.js";import"./folder-open-CIWhCFhy.js";import"./pencil-C2cyk8cg.js";import"./message-square-BDdDilNB.js";import"./ticket-l9bl0kcm.js";import"./megaphone-DpQsxotQ.js";import"./package-DKB1lvtO.js";import"./circle-user-BeB3uaA1.js";import"./folder-kanban-B8jlMC6s.js";import"./settings-Baim_Eei.js";import"./briefcase-CdSp4ViD.js";import"./chart-line-ohAz7u_s.js";import"./index-O12prPmO.js";import"./chevron-up-B89bkR-F.js";import"./en-US-Bfz1jvxT.js";import"./differenceInCalendarDays-D4nmWE3G.js";import"./getTimezoneOffsetInMilliseconds-DsfBWtEI.js";const B={hasTags:[],lacksTags:[],status:"active",churnRisk:"any",engagementMin:null,engagementMax:null,subscribedAfter:"",subscribedBefore:""};function as(){const[a,c]=b.useState([]),[f,j]=b.useState(!0),[r,u]=b.useState(null),[l,n]=b.useState(null),[i,H]=b.useState([]);b.useEffect(()=>{w()},[]);async function w(){j(!0);const[{data:s},{data:t}]=await Promise.all([h.from("subscriber_segments").select("*").order("updated_at",{ascending:!1}),h.from("newsletter_subscribers").select("list_tags")]);c(s||[]);const o=new Set;(t||[]).forEach(x=>(x.list_tags||[]).forEach(v=>o.add(v))),H(Array.from(o).sort()),j(!1)}async function M(s){let t=h.from("newsletter_subscribers").select("id,list_tags,is_active,confirmed_at,churn_risk,engagement_score,subscribed_at");s.status==="active"?t=t.eq("is_active",!0):s.status==="inactive"?t=t.eq("is_active",!1):s.status==="confirmed"?t=t.not("confirmed_at","is",null):s.status==="unconfirmed"&&(t=t.is("confirmed_at",null)),s.churnRisk&&s.churnRisk!=="any"&&(t=t.eq("churn_risk",s.churnRisk)),s.subscribedAfter&&(t=t.gte("subscribed_at",s.subscribedAfter)),s.subscribedBefore&&(t=t.lte("subscribed_at",s.subscribedBefore));const{data:o,error:x}=await t;return x?(g.error(x.message),0):(o||[]).filter(E=>{const L=E.list_tags||[];if(s.hasTags.some(N=>!L.includes(N))||s.lacksTags.some(N=>L.includes(N)))return!1;const R=E.engagement_score??0;return!(s.engagementMin!==null&&R<s.engagementMin||s.engagementMax!==null&&R>s.engagementMax)}).length}async function I(){var v;if(!r)return;if(!r.name.trim()){g.error("Name required");return}const{data:s}=await h.auth.getUser(),t={name:r.name.trim(),description:r.description.trim()||null,filter_criteria:r.filter,is_dynamic:r.isDynamic,subscriber_count:l??0,created_by:((v=s.user)==null?void 0:v.id)??null},{error:o,data:x}=r.id?await h.from("subscriber_segments").update({...t,updated_at:new Date().toISOString()}).eq("id",r.id).select("id").single():await h.from("subscriber_segments").insert(t).select("id").single();if(o){g.error(o.message);return}await q({action:r.id?"segment.update":"segment.create",entity_id:x==null?void 0:x.id,details:{name:r.name,dynamic:r.isDynamic}}),g.success("Saved"),u(null),n(null),w()}async function O(s){if(!confirm(`Delete segment "${s.name}"?`))return;const{error:t}=await h.from("subscriber_segments").delete().eq("id",s.id);if(t){g.error(t.message);return}await q({action:"segment.delete",entity_id:s.id,details:{name:s.name}}),g.success("Deleted"),w()}async function U(s){const t=await M(s.filter_criteria),{error:o}=await h.from("subscriber_segments").update({subscriber_count:t,updated_at:new Date().toISOString()}).eq("id",s.id);if(o){g.error(o.message);return}g.success(`${s.name}: ${t} subscriber(s)`),w()}return e.jsx(z,{children:e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex items-center gap-3 flex-wrap",children:[e.jsx(p,{asChild:!0,variant:"ghost",size:"sm",children:e.jsxs(se,{to:"/admin/subscribers/manage",children:[e.jsx(re,{className:"w-4 h-4 mr-2"}),"Back"]})}),e.jsxs("div",{className:"flex-1",children:[e.jsx("h1",{className:"text-3xl font-display font-bold",children:"Segments"}),e.jsx("p",{className:"text-muted-foreground",children:"Saved filters for targeting subsets of the list. Read-only â does not wire to sends."})]}),e.jsxs(G,{open:!!r,onOpenChange:s=>{s||(u(null),n(null))},children:[e.jsx(J,{asChild:!0,children:e.jsxs(p,{onClick:()=>{u({name:"",description:"",isDynamic:!0,filter:{...B}}),n(null)},children:[e.jsx(ie,{className:"w-4 h-4 mr-2"}),"New segment"]})}),r&&e.jsx(le,{value:r,onChange:u,allTags:i,onPreview:async()=>{const s=await M(r.filter);n(s),g.success(`Matches ${s} subscriber(s)`)},previewCount:l,onSave:I})]})]}),f?e.jsx(_,{children:e.jsx(C,{className:"py-12 text-center text-muted-foreground",children:"Loadingâ¦"})}):a.length===0?e.jsx(_,{children:e.jsx(C,{className:"py-12 text-center text-muted-foreground",children:"No segments yet. Create one to save a reusable filter."})}):e.jsx("div",{className:"grid gap-3",children:a.map(s=>e.jsxs(_,{children:[e.jsx(V,{children:e.jsxs("div",{className:"flex items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx($,{className:"text-lg",children:s.name}),s.description&&e.jsx(F,{children:s.description})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs(S,{variant:"secondary",children:[e.jsx(te,{className:"w-3 h-3 mr-1"}),s.subscriber_count??0]}),e.jsx(S,{variant:"outline",children:s.is_dynamic?"Dynamic":"Static"})]})]})}),e.jsx(C,{children:e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsxs(p,{size:"sm",variant:"outline",onClick:()=>U(s),children:[e.jsx(ae,{className:"w-4 h-4 mr-2"}),"Recount"]}),e.jsx(p,{size:"sm",variant:"outline",onClick:()=>{u({id:s.id,name:s.name,description:s.description||"",isDynamic:s.is_dynamic,filter:{...B,...s.filter_criteria||{}}}),n(s.subscriber_count)},children:"Edit"}),e.jsxs(p,{size:"sm",variant:"ghost",className:"text-destructive",onClick:()=>O(s),children:[e.jsx(ne,{className:"w-4 h-4 mr-2"}),"Delete"]}),e.jsxs("span",{className:"text-xs text-muted-foreground self-center ml-auto",children:["Updated ",ce(new Date(s.updated_at),"MMM d, yyyy HH:mm")]})]})})]},s.id))})]})})}function P({label:a,value:c,onChange:f,allTags:j}){return e.jsxs("div",{children:[e.jsx(d,{children:a}),e.jsx("div",{className:"flex flex-wrap gap-1 mt-1 min-h-[28px]",children:c.map(r=>e.jsxs(S,{variant:"secondary",className:"text-xs gap-1 cursor-pointer",onClick:()=>f(c.filter(u=>u!==r)),children:[r," Ã"]},r))}),e.jsxs(k,{onValueChange:r=>{c.includes(r)||f([...c,r])},children:[e.jsx(D,{className:"mt-2",children:e.jsx(T,{placeholder:"+ add tag"})}),e.jsx(A,{children:j.filter(r=>!c.includes(r)).map(r=>e.jsx(m,{value:r,children:r},r))})]})]})}function le({value:a,onChange:c,allTags:f,onPreview:j,previewCount:r,onSave:u}){const l=a.filter,n=i=>c({...a,filter:{...l,...i}});return e.jsxs(K,{className:"max-w-2xl max-h-[90vh] overflow-y-auto",children:[e.jsxs(Q,{children:[e.jsx(W,{children:a.id?"Edit segment":"New segment"}),e.jsx(X,{children:"Define a filter. Click Preview to count matches before saving."})]}),e.jsxs("div",{className:"space-y-3 py-2",children:[e.jsxs("div",{children:[e.jsx(d,{children:"Name *"}),e.jsx(y,{value:a.name,onChange:i=>c({...a,name:i.target.value})})]}),e.jsxs("div",{children:[e.jsx(d,{children:"Description"}),e.jsx(Z,{rows:2,value:a.description,onChange:i=>c({...a,description:i.target.value})})]}),e.jsxs("div",{className:"flex items-center justify-between p-3 border rounded",children:[e.jsxs("div",{children:[e.jsx(d,{children:"Dynamic"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Re-evaluates every open. Off = snapshot count only."})]}),e.jsx(ee,{checked:a.isDynamic,onCheckedChange:i=>c({...a,isDynamic:i})})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(P,{label:"Has tags (ALL)",value:l.hasTags,onChange:i=>n({hasTags:i}),allTags:f}),e.jsx(P,{label:"Lacks tags (NONE)",value:l.lacksTags,onChange:i=>n({lacksTags:i}),allTags:f})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsxs("div",{children:[e.jsx(d,{children:"Status"}),e.jsxs(k,{value:l.status,onValueChange:i=>n({status:i}),children:[e.jsx(D,{children:e.jsx(T,{})}),e.jsxs(A,{children:[e.jsx(m,{value:"any",children:"Any"}),e.jsx(m,{value:"active",children:"Active"}),e.jsx(m,{value:"inactive",children:"Inactive"}),e.jsx(m,{value:"confirmed",children:"Confirmed"}),e.jsx(m,{value:"unconfirmed",children:"Unconfirmed"})]})]})]}),e.jsxs("div",{children:[e.jsx(d,{children:"Churn risk"}),e.jsxs(k,{value:l.churnRisk,onValueChange:i=>n({churnRisk:i}),children:[e.jsx(D,{children:e.jsx(T,{})}),e.jsxs(A,{children:[e.jsx(m,{value:"any",children:"Any"}),e.jsx(m,{value:"low",children:"Low"}),e.jsx(m,{value:"medium",children:"Medium"}),e.jsx(m,{value:"high",children:"High"})]})]})]})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsxs("div",{children:[e.jsx(d,{children:"Engagement min (%)"}),e.jsx(y,{type:"number",value:l.engagementMin??"",onChange:i=>n({engagementMin:i.target.value===""?null:Number(i.target.value)})})]}),e.jsxs("div",{children:[e.jsx(d,{children:"Engagement max (%)"}),e.jsx(y,{type:"number",value:l.engagementMax??"",onChange:i=>n({engagementMax:i.target.value===""?null:Number(i.target.value)})})]})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsxs("div",{children:[e.jsx(d,{children:"Subscribed after"}),e.jsx(y,{type:"date",value:l.subscribedAfter,onChange:i=>n({subscribedAfter:i.target.value})})]}),e.jsxs("div",{children:[e.jsx(d,{children:"Subscribed before"}),e.jsx(y,{type:"date",value:l.subscribedBefore,onChange:i=>n({subscribedBefore:i.target.value})})]})]}),r!==null&&e.jsxs("div",{className:"p-3 rounded bg-accent/10 border border-accent/30 text-sm",children:[e.jsx("strong",{children:r})," subscriber(s) match this filter right now."]})]}),e.jsxs(Y,{children:[e.jsx(p,{variant:"outline",onClick:j,children:"Preview count"}),e.jsx(p,{onClick:u,children:"Save segment"})]})]})}export{as 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.