PageSourceSearch

https://pblfg.com/assets/BroadcastsTab-CUo4fz8E.js

js pblfg.com collected 2026-09-24 14:50:53 UTC 37,057 bytes, 1 lines download raw bytes

1import{r as f,j as e}from"./react-vendor-Q2BSRknM.js";import{eb as Ye,U as _,_ as de,V as fe,R as ae,J as Z,K as J,L as W,N as ee,O as y,B as Q,h as U,Q as F,s as x,r as Te,v as Fe,c as He,w as Le,ab as Ke,A as _e,y as be,z as ke,E as Se,F as Ce,G as De,H as Ee,I as qe}from"./index-CuraQpvj.js";import{A as ue,a as Ne,l as Xe}from"./Admin-XbDVNFMU.js";import{a8 as Qe,L as me,a9 as Ze,E as Me,bq as Je,bB as ge,e as Be,U as xe,u as je,aX as ve,M as We,n as es,ah as ss,bC as ts,b as as,X as ns,R as is,T as Ae}from"./lucide-DhlFjs1-.js";import{u as ne,b as rs}from"./query-BLOP9k_M.js";import{S as ls}from"./scroll-area-G9RincEy.js";import{c as Oe}from"./date-utils-DaNoSKVa.js";import"./capacitor-DSpR9wll.js";import"./ui-radix-DzQ_orwq.js";import"./supabase-DoZmW4Yf.js";const Ie=[{value:"ios",label:"🍎 iOS App"},{value:"android",label:"🤖 Android"},{value:"web",label:"🌐 Web / Desktop"}];function cs(){const{config:r,isLoading:d,updateConfig:S}=Ye(),[a,m]=f.useState({enabled:!1,message:"",link_url:"",link_text:"",device_links:{},show_on:["ios","android","web"],type:"info",dismissible:!0}),[s,c]=f.useState(!1),[h,C]=f.useState(!1),[H,$]=f.useState(!1);f.useEffect(()=>{if(!d){const i=r.device_links&&Object.keys(r.device_links).length>0;$(!!i),m({enabled:r.enabled,message:r.message||"",link_url:r.link_url||"",link_text:r.link_text||"",device_links:r.device_links||{},show_on:r.show_on||["ios","android","web"],type:r.type||"info",dismissible:r.dismissible!==!1})}},[r,d]),f.useEffect(()=>{const i=JSON.stringify(a)!==JSON.stringify({enabled:r.enabled,message:r.message||"",link_url:r.link_url||"",link_text:r.link_text||"",device_links:r.device_links||{},show_on:r.show_on||["ios","android","web"],type:r.type||"info",dismissible:r.dismissible!==!1});C(i)},[a,r]);const V=async()=>{if(!a.message.trim()&&a.enabled){F({title:"Message required",description:"Add a message before enabling the banner.",variant:"destructive"});return}c(!0);try{await S(a),F({title:"Banner updated",description:a.enabled?"Announcement is now live.":"Banner has been turned off."})}catch(i){F({title:"Error",description:i.message,variant:"destructive"})}finally{c(!1)}},G=async i=>{if(i&&!a.message.trim()){F({title:"Message required",description:"Add a message before enabling.",variant:"destructive"});return}m(l=>({...l,enabled:i})),c(!0);try{await S({...a,enabled:i}),F({title:i?"Banner is live":"Banner turned off"})}catch(l){F({title:"Error",description:l.message,variant:"destructive"})}finally{c(!1)}},L=i=>{m(l=>{const p=l.show_on||[],g=p.includes(i)?p.filter(I=>I!==i):[...p,i];return{...l,show_on:g.length>
10?g:[i]}})},D=(i,l,p)=>{m(g=>{var I;return{...g,device_links:{...g.device_links,[i]:{...(I=g.device_links)==null?void 0:I[i],[l]:p}}}})};return e.jsx(ue,{title:"Announcement Banner",description:"App-wide banner shown above the bottom nav",icon:Qe,collapsible:!0,defaultOpen:!0,storageKey:"announcement-banner",headerAction:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(U,{variant:r.enabled?"default":"secondary",className:"text-xs",children:r.enabled?"LIVE":"OFF"}),e.jsx(fe,{checked:a.enabled,onCheckedChange:G,disabled:s})]}),children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(_,{htmlFor:"banner-message",children:"Message"}),e.jsx(Ne,{id:"banner-message",placeholder:"e.g. A new app update is available with exciting features!",value:a.message,onChange:i=>m(l=>({...l,message:i.target.value})),rows:2,className:"resize-none"})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(_,{children:"Show On"}),e.jsx("div",{className:"flex flex-wrap gap-3",children:Ie.map(i=>e.jsxs("label",{className:"flex items-center gap-1.5 text-sm cursor-pointer",children:[e.jsx(de,{checked:(a.show_on||[]).includes(i.value),onCheckedChange:()=>L(i.value)}),i.label]},i.value))})]}),e.jsx("div",{className:"space-y-1.5",children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(fe,{checked:H,onCheckedChange:i=>{$(i),m(i?l=>{var p,g,I,B,o,N,u,O;return{...l,device_links:{...l.device_links,ios:{url:((g=(p=l.device_links)==null?void 0:p.ios)==null?void 0:g.url)||"https://apps.apple.com/us/app/pblfg/id6755119460",text:((B=(I=l.device_links)==null?void 0:I.ios)==null?void 0:B.text)||"Update"},android:{url:((N=(o=l.device_links)==null?void 0:o.android)==null?void 0:N.url)||"https://play.google.com/store/apps/details?id=com.cc.pbpulse.app",text:((O=(u=l.device_links)==null?void 0:u.android)==null?void 0:O.text)||"Update"}}}}:l=>({...l,device_links:{}}))}}),e.jsx(_,{className:"text-sm cursor-pointer",children:"Different links per device"})]})}),H?e.jsx("div",{className:"space-y-3",children:Ie.filter(i=>(a.show_on||[]).includes(i.value)).map(i=>{var l,p,g,I;return e.jsxs("div",{className:"space-y-1.5 p-3 rounded-lg border border-border/50 bg-muted/30",children:[e.jsxs(_,{className:"text-xs text-muted-foreground",children:[i.label," Link"]}),e.jsxs("div",{className:"grid grid-cols-2 gap-2",children:[e.jsx(ae,{placeholder:i.value==="ios"?"https://apps.apple.com/...":i.value==="android"?"https://play.google.com/...":"https://...",value:((p=(l=a.device_links)==null?void 0:l[i.value])==null?void 0:p.url)||"",onChange:B=>D(i.value,"url",B.target.value)}),e.jsx(ae,{placeholder:"Update Now",value:((I=(g=a.device_links)==null?void 0:g[i.value])==null?void 0:I.text)||"",onChange:B=>D(i.value,"text",B.target.value)})]})]},i.value)})}):e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(_,{htmlFor:"banner-link-url",children:"Link URL (optional)"}),e.jsx(ae,{id:"banner-link-url",placeholder:"https://...",value:a.link_url,onChange:i=>m(l=>({...l,link_url:i.target.value}))})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(_,{htmlFor:"banner-link-text",children:"Link Text"}),e.jsx(ae,{id:"banner-link-text",placeholder:"Update Now",value:a.link_text,onChange:i=>m(l=>({...l,link_text:i.target.value}))})]})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(_,{children:"Banner Type"}),e.jsxs(Z,{value:a.type,onValueChange:i=>m(l=>({...l,type:i})),children:[e.jsx(J,{children:e.jsx(W,{})}),e.jsxs(ee,{children:[e.jsx(y,{value:"info",children:"ℹ️ Info"}),e.jsx(y,{value:"update",children:"🆕 Update"}),e.jsx(y,{value:"warning",children:"⚠️ Warning"})]})]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(_,{children:"Dismissible"}),e.jsxs("div",{className:"flex items-center gap-2 h-10",children:[e.jsx(fe,{checked:a.dismissible,onCheckedChange:i=>m(l=>({...l,dismissible:i}))}),e.jsx("span",{className:"text-sm text-muted-foreground",children:a.dismissible?"Users can dismiss":"Always visible"})]})]})]}),h&&e.jsxs(Q,{onClick:V,disabled:s,className:"w-full gap-2",children:[s?e.jsx(me,{className:"h-4 w-4 animate-spin"}):e.jsx(Ze,{className:"h-4 w-4"}),"Save Changes"]}),(()=>{var p;const i=!!(a.link_url||Object.values(a.device_links||{}).some(g=>g==null?void 0:g.url)),l=a.link_text||((p=Object.values(a.device_links||{}).find(g=>g==null?void 0:g.text))==null?void 0:p.text)||"Learn more";return a.message?e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(_,{className:"text-muted-foreground text-xs",children:"Preview"}),e.jsx("div",{className:"rounded-lg overflow-hidden border border-border/50 bg-primary/90 text-primary-foreground px-4 py-2.5 text-[13px] font-medium flex items-center gap-1.5",children:a.type==="update"&&i?e.jsxs(e.Fragment,{children:[e.jsx(Me,{className:"h-3.5 w-3.5 shrink-0"}),e.jsx("span",{className:"underline font-semibold shrink-0",children:l}),e.jsx("span",{className:"flex-1 min-w-0",children:a.message})]}):e.jsx(e.Fragment,{children:e.jsxs("span",{className:"flex-1 min-w-0",children:[a.message,i&&e.jsxs("span",{className:"ml-1.5 underline font-semibold",children:[l," ↗"]})]})})})]}):null})()]})})}function Ue({tournamentId:r,selectedMatchId:d,onSelect:S}){const{data:a=[]}=ne({queryKey:["live-matches-for-dedup",r],queryFn:async()=>{let s=x.from("matches").select("id, team1, team2, round, court, event, tournament").eq("status","live").order("updated_at",{ascending:!1}).limit(50);if(r){const{data:C}=await x.from("tournaments").select("name").eq("id",r).single();C&&(s=s.eq("tournament",C.name))}const{data:c,error:h}=await s;return h?[]:c||[]},refetchInterval:3e4}),m=s=>s.map(c=>c.split(" ").pop()).join("/");return e.jsxs("div",{className:"space-y-1.5",children:[e.jsxs(_,{className:"text-xs flex items-center gap-1.5",children:[e.jsx(Je,{className:"h-3 w-3"}),"Link to Match (optional dedup)"]}),e.jsxs(Z,{value:d??"__none__",onValueChange:s=>S(s==="__none__"?null:s),children:[e.jsx(J,{className:"h-9 text-sm",children:e.jsx(W,{placeholder:"No match linked"})}),e.jsxs(ee,{children:[e.jsx(y,{value:"__none__",children:"No match linked"}),a.map(s=>e.jsxs(y,{value:s.id,children:[m(s.team1)," vs ",m(s.team2),s.roun
1d?` - ${s.round}`:"",s.court?` (${s.court})`:""]},s.id))]})]}),d&&e.jsx("p",{className:"text-[10px] text-muted-foreground",children:"Users who already got a notification for this match will be skipped"})]})}const os=({tournamentId:r})=>{const[d,S]=f.useState(!1),{data:a=[]}=ne({queryKey:["venue-notification-history",r],queryFn:async()=>{let c=x.from("admin_activity_log").select("*").eq("action_type","venue_notification_sent").order("created_at",{ascending:!1}).limit(50);r&&(c=c.eq("target_id",r));const{data:h,error:C}=await c;return C?[]:h||[]},enabled:d,staleTime:3e4}),m=r?{}:a.reduce((c,h)=>{const C=h.target_name||"Unknown Event";return c[C]||(c[C]=[]),c[C].push(h),c},{}),s=a.length;return e.jsxs(Te,{open:d,onOpenChange:S,children:[e.jsxs(Fe,{className:"flex items-center gap-2 w-full py-2 px-3 rounded-lg bg-muted/30 border border-border/20 hover:bg-muted/50 transition-colors text-left",children:[e.jsx(ge,{className:"w-3.5 h-3.5 text-muted-foreground shrink-0"}),e.jsx("span",{className:"text-xs font-medium flex-1",children:"Notification History"}),d&&s>0&&e.jsxs("span",{className:"text-[10px] text-muted-foreground",children:[s," sent"]}),e.jsx(Be,{className:He("w-3.5 h-3.5 text-muted-foreground transition-transform",d&&"rotate-180")})]}),e.jsx(Le,{children:e.jsx(ls,{className:"max-h-[250px] mt-2",children:a.length===0?e.jsx("p",{className:"text-xs text-muted-foreground py-4 text-center",children:"No notifications sent yet."}):r?e.jsx("div",{className:"space-y-1.5",children:a.map(c=>e.jsx(Re,{item:c},c.id))}):e.jsx("div",{className:"space-y-3",children:Object.entries(m).map(([c,h])=>e.jsx(ds,{name:c,items:h},c))})})})]})},ds=({name:r,items:d})=>{const[S,a]=f.useState(!0);return e.jsxs(Te,{open:S,onOpenChange:a,children:[e.jsxs(Fe,{className:"flex items-center gap-2 w-full text-left py-1.5 px-2 rounded hover:bg-muted/30",children:[e.jsx(Be,{className:He("w-3 h-3 text-muted-foreground transition-transform",S&&"rotate-180")}),e.jsx("span",{className:"text-xs font-semibold truncate flex-1",children:r}),e.jsx("span",{className:"text-[10px] text-muted-foreground",children:d.length})]}),e.jsx(Le,{children:e.jsx("div",{className:"space-y-1.5 pl-5 pt-1",children:d.map(m=>e.jsx(Re,{item:m},m.id))})})]})},Re=({item:r})=>{const d=r.details||{},S=d.title||"Untitled",a=d.message||"",m=d.users_targeted_auth||0,s=d.users_targeted_anon||0,c=d.users_targeted||m+s,h=Oe(new Date(r.created_at),{addSuffix:!0});return e.jsxs("div",{className:"p-2 rounded-md bg-muted/20 border border-border/10 space-y-1",children:[e.jsxs("div",{className:"flex items-start justify-between gap-2",children:[e.jsx("p",{className:"text-xs font-medium leading-snug truncate flex-1",children:S}),e.jsxs("div",{className:"flex items-center gap-1 shrink-0",children:[e.jsx(xe,{className:"w-3 h-3 text-muted-foreground"}),e.jsx("span",{className:"text-[10px] text-muted-foreground",children:c})]})]}),a&&e.jsx("p",{className:"text-[11px] text-muted-foreground line-clamp-2",children:a}),e.jsxs("div",{className:"flex items-center gap-2 text-[10px] text-muted-foreground/70 flex-wrap",children:[e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx(je,{className:"w-2.5 h-2.5"}),h]}),m>0&&e.jsxs("span",{className:"px-1 py-0.5 rounded bg-primary/10 text-primary text-[9px]",children:[m," signed in"]}),s>0&&e.jsxs("span",{className:"px-1 py-0.5 rounded bg-muted text-[9px]",children:[s," anon"]})]})]})},us=({tournamentId:r,tournamentName:d})=>{var I,B;const{toast:S}=Ke(),[a,m]=f.useState(r||""),[s,c]=f.useState(""),[h,C]=f.useState(""),[H,$]=f.useState(null),[V,G]=f.useState(!1),L=r||a,{data:D=[]}=ne({queryKey:["tournaments-for-venue-notif"],queryFn:async()=>{const o=new Date(Date.now()-1728e5).toISOString(),{data:N,error:u}=await x.from("tournaments").select("id, name, display_name, start_date, end_date, is_challenger, is_pro_event, hide_from_display, deleted_at").is("deleted_at",null).or(`end_date.gte.${o},start_date.gte.${o}`).order("start_date",{ascending:!0}).limit(50);return u?[]:(N||[]).filter(O=>!/test/i.test(`${O.display_name||""} ${O.name||""}`))},enabled:!r});f.useEffect(()=>{if(r||V||D.length===0)return;const o=new Date,N=(j,E=0)=>j?new Date(j).getTime():E,u=j=>j?1:0,O=j=>j?0:1,ie=[...D].filter(j=>{const E=N(j.start_date,Number.MAX_SAFE_INTEGER),R=j.end_date?N(j.end_date,Number.MIN_SAFE_INTEGER):E+5*24*60*60*1e3;return E<=o.getTime()&&R>=o.getTime()}).sort((j,E)=>{const R=u(j.is_challenger)-u(E.is_challenger);if(R!==0)return R;const Y=O(j.is_pro_event)-O(E.is_pro_event);return Y!==0?Y:N(j.start_date,Number.MAX_SAFE_INTEGER)-N(E.start_date,Number.MAX_SAFE_INTEGER)})[0];if(ie){m(ie.id),G(!0);return}const le=[...D].filter(j=>N(j.start_date,Number.MIN_SAFE_INTEGER)>o.getTime()).sort((j,E)=>{const R=N(j.start_date,Number.MAX_SAFE_INTEGER)-N(E.start_date,Number.MAX_SAFE_INTEGER);if(R!==0)return R;const Y=u(j.is_challenger)-u(E.is_challenger);return Y!==0?Y:O(j.is_pro_event)-O(E.is_pro_event)})[0];if(le){m(le.id),G(!0);return}const ce=[...D].sort((j,E)=>N(E.start_date)-N(j.start_date))[0];ce&&(m(ce.id),G(!0))},[D,r,V]);const i=d||((I=D.find(o=>o.id===a))==null?void 0:I.display_name)||((B=D.find(o=>o.id===a))==null?void 0:B.name)||"the venue",{data:l=0,refetch:p}=ne({queryKey:["venue_presence_count",L],queryFn:async()=>
1{if(!L)return 0;const o=new Date(Date.now()-12*60*60*1e3).toISOString(),{count:N,error:u}=await x.from("venue_presence").select("*",{count:"exact",head:!0}).eq("tournament_id",L).eq("is_at_venue",!0).gte("last_seen_at",o);return u?0:N||0},enabled:!!L,refetchInterval:3e4}),g=rs({mutationFn:async()=>{const{data:o,error:N}=await x.functions.invoke("send-venue-notification",{body:{tournament_id:L,title:s,message:h,match_id:H}});if(N)throw N;return o},onSuccess:o=>{S({title:"Notification sent",description:`Sent to ${o.users_targeted} user(s) at the venue.${o.skipped_dedup?` ${o.skipped_dedup} skipped (already notified).`:""}`}),c(""),C(""),$(null),p()},onError:o=>{S({title:"Failed to send",description:o.message||"Something went wrong",variant:"destructive"})}});return e.jsxs("div",{className:"space-y-3",children:[L&&e.jsxs("div",{className:"flex items-center gap-3 p-3 rounded-lg bg-primary/10 border border-primary/20",children:[e.jsx("div",{className:"flex items-center justify-center h-10 w-10 rounded-full bg-primary/20",children:e.jsx(xe,{className:"h-5 w-5 text-primary"})}),e.jsxs("div",{children:[e.jsx("p",{className:"text-2xl font-bold text-primary",children:l}),e.jsx("p",{className:"text-[11px] text-muted-foreground",children:"users at venue now"})]})]}),!r&&e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(_,{className:"text-xs",children:"Event"}),e.jsxs(Z,{value:a,onValueChange:m,children:[e.jsx(J,{className:"h-9 text-sm",children:e.jsx(W,{placeholder:"Select an event..."})}),e.jsx(ee,{children:D.map(o=>e.jsx(y,{value:o.id,children:o.display_name||o.name},o.id))})]})]}),L?e.jsxs(e.Fragment,{children:[e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Send a push notification to all users (signed in & anonymous) currently at ",i," (within 10 km)."]}),e.jsx(ae,{placeholder:"Notification title",value:s,onChange:o=>c(o.target.value),className:"h-9 text-sm"}),e.jsx(Ne,{placeholder:"Message body...",value:h,onChange:o=>C(o.target.value),className:"text-sm min-h-[60px] resize-none"}),e.jsx(Ue,{tournamentId:L,selectedMatchId:H,onSelect:$}),e.jsxs(Q,{onClick:()=>g.mutate(),disabled:!s.trim()||!h.trim()||g.isPending||l===0,size:"sm",className:"w-full gap-1.5",children:[g.isPending?e.jsx(me,{className:"h-3.5 w-3.5 animate-spin"}):e.jsx(ve,{className:"h-3.5 w-3.5"}),"Send to ",l," user",l!==1?"s":""," at venue"]}),e.jsx(os,{tournamentId:L})]}):e.jsx("p",{className:"text-xs text-muted-foreground py-2",children:"Select an event to send venue notifications."})]})},Ss=f.memo(function(){const[d,S]=f.useState(""),[a,m]=f.useState(""),[s,c]=f.useState({platform:"all",activeInDays:null,hasFollowedPlayers:null,excludeRecentBroadcast:!1,excludeRecentHours:24,quietHoursEnabled:!1,quietHoursStart:21,quietHoursEnd:8}),[h,C]=f.useState(null),[H,$]=f.useState("none"),[V,G]=f.useState(!1),[L,D]=f.useState(!1),[i,l]=f.useState(!1),[p,g]=f.useState(null),[I,B]=f.useState(!1),[o,N]=f.useState(!1),{data:u,isLoading:O}=ne({queryKey:["broadcast-audience-stats"],queryFn:async()=>{const{count:t}=await x.from("device_tokens").select("*",{count:"exact",head:!0}),{count:n}=await x.from("device_tokens").select("*",{count:"exact",head:!0}).eq("platform","ios"),{count:T}=await x.from("device_tokens").select("*",{count:"exact",head:!0}).eq("platform","android"),{data:M}=await x.from("profiles").select("id").gte("updated_at",new Date(Date.now()-7*24*60*60*1e3).toISOString()),{count:b}=await x.from("device_tokens").select("*",{count:"exact",head:!0}).in("user_id",(M==null?void 0:M.map(z=>z.id))||[]),{data:K}=await x.from("profiles").select("id").gte("updated_at",new Date(Date.now()-30*24*60*60*1e3).toISOString()),{count:se}=await x.from("device_tokens").select("*",{count:"exact",head:!0}).in("user_id",(K==null?void 0:K.map(z=>z.id))||[]),{data:P}=await x.from("user_notification_preferences").select("user_id").limit(1e3),te=[...new Set((P==null?void 0:P.map(z=>z.user_id))||[])],{count:re}=await x.from("device_tokens").select("*",{count:"exact",head:!0}).in("user_id",te);return{total:t||0,ios:n||0,android:T||0,activeIn7Days:b||0,activeIn30Days:se||0,withFollowedPlayers:re||0}},staleTime:6e4}),{data:ie=[],isLoading:le,refetch:ce}=ne({queryKey:["broadcast-history"],queryFn:async()=>{const{data:t,error:n}=await x.from("admin_activity_log").select("id, admin_email, target_name, details, created_at").eq("action_type","broadcast").eq("action_category","notification").order("created_at",{ascending:!1}).limit(20);if(n)throw n;return t||[]},staleTime:3e4}),j=async()=>{B(!0);try{let t=x.from("device_tokens").select("user_id",{count:"exact",head:!0});s.platform!=="all"&&(t=t.eq("platform",s.platform));const{count:n}=await t;let T=n||0;
1if(s.activeInDays){const M=s.activeInDays===7?((u==null?void 0:u.activeIn7Days)||0)/((u==null?void 0:u.total)||1):((u==null?void 0:u.activeIn30Days)||0)/((u==null?void 0:u.total)||1);T=Math.round(T*M)}if(s.hasFollowedPlayers){const M=((u==null?void 0:u.withFollowedPlayers)||0)/((u==null?void 0:u.total)||1);T=Math.round(T*M)}g(T)}catch(t){console.error("Error estimating recipients:",t)}finally{B(!1)}};f.useEffect(()=>{u&&j()},[s,u]);const E=async()=>{if(!d.trim()||!a.trim()){F.error("Please fill in both title and message");return}D(!0)},R=async()=>{if(!d.trim()||!a.trim()){F.error("Please fill in both title and message");return}N(!0);try{const{data:{session:t}}=await x.auth.getSession();if(!t)throw new Error("Not authenticated");const{error:n}=await x.functions.invoke("send-push-notification",{body:{user_id:t.user.id,title:d,body:a,data:{type:"broadcast_test",timestamp:new Date().toISOString(),...H!=="none"?{route:H}:{}}},headers:{Authorization:`Bearer ${t.access_token}`}});if(n)throw n;F.success("Test notification sent to your device")}catch(t){console.error("Test notification error:",t),F.error(t.message||"Failed to send test notification")}finally{N(!1)}},Y=async()=>{G(!0),D(!1),l(!1);try{const{data:{session:t}}=await x.auth.getSession();if(!t)throw new Error("Not authenticated");let n=x.from("device_tokens").select("token, platform, user_id");s.platform!=="all"&&(n=n.eq("platform",s.platform));const{data:T,error:M}=await n;if(M)throw M;if(!T||T.length===0){F.error("No recipients found for this audience");return}let b=T;if(s.activeInDays){const q=new Date(Date.now()-s.activeInDays*24*60*60*1e3).toISOString(),{data:v}=await x.from("profiles").select("id").gte("updated_at",q),k=new Set((v==null?void 0:v.map(A=>A.id))||[]);b=b.filter(A=>k.has(A.user_id))}if(s.hasFollowedPlayers){const{data:q}=await x.from("user_notification_preferences").select("user_id"),v=new Set((q==null?void 0:q.map(k=>k.user_id))||[]);b=b.filter(k=>v.has(k.user_id))}if(b.length===0){F.error("No recipients match the selected filters");return}let K=0;if(h){const q=[...new Set(b.map(k=>k.user_id))],{data:v}=await x.from("notification_history").select("user_id").eq("match_id",h).in("user_id",q);if(v&&v.length>0){const k=new Set(v.map(w=>w.user_id)),A=b.length;b=b.filter(w=>!k.has(w.user_id)),K=A-b.length,console.log(`[Broadcast] Skipped ${K} users who already got notification for match ${h}`)}}let se=b,P=[],te=0;if(s.quietHoursEnabled){const q=[...new Set(b.map(w=>w.user_id).filter(Boolean))],{data:v}=await x.from("profiles").select("id, timezone").in("id",q),k=new Map((v==null?void 0:v.map(w=>[w.id,w.timezone||"America/New_York"]))||[]),A=new Date;se=[],P=[];for(const w of b){const X=k.get(w.user_id)||"America/New_York";try{const he=parseInt(A.toLocaleString("en-US",{timeZone:X,hour:"numeric",hour12:!1}));he>=s.quietHoursEnd&&he<s.quietHoursStart?se.push(w):P.push(w)}catch{se.push(w)}}}let re=0,z=0;for(const q of se)try{await x.functions.invoke("send-push-notification",{body:{user_id:q.user_id,title:d,body:a,data:{type:"broadcast",timestamp:new Date().toISOString(),...h?{matchId:h}:{},...H!=="none"?{route:H}:{}}},headers:{Authorization:`Bearer ${t.access_token}`}}),re++}catch{z++}if(P.length>0){const q=new Map;if(s.quietHoursEnabled){const k=[...new Set(P.map(w=>w.user_id).filter(Boolean))],{data:A}=await x.from("profiles").select("id, timezone").in("id",k);A==null||A.forEach(w=>q.set(w.id,w.timezone||"America/New_York"))}const v=new Date;for(const k of P)try{const A=q.get(k.user_id)||"America/New_York",w=new Date(v.toLocaleString("en-US",{timeZone:A})),X=new Date(w);X.setHours(s.quietHoursEnd,0,0,0),X<=w&&X.setDate(X.getDate()+1);const he=new Date(X.toLocaleString("en-US",{timeZone:"UTC"})).toISOString(),ze=new Intl.DateTimeFormat("en-US",{timeZone:A,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1}).formatToParts(v),oe=Ve=>{var we;return((we=ze.find(Ge=>Ge.type===Ve))==null?void 0:we.value)||"0"},xs=parseInt(oe("year")),hs=parseInt(oe("month")),ps=parseInt(oe("day")),pe=parseInt(oe("hour"));let ye=new Date(v);const $e=pe<s.quietHoursEnd?s.quietHoursEnd-pe:24-pe+s.quietHoursEnd;ye=new Date(v.getTime()+$e*60*60*1e3),await x.from("deferred_notifications").insert({user_id:k.user_id,device_token:k.token,platform:k.platform,title:d,body:a,data:{type:"broadcast",timestamp:new Date().toISOString(),...h?{matchId:h}:{},...H!=="none"?{route:H}:{}},deliver_after:ye.toISOString(),status:"pending",reason:`Quiet hours (${s.quietHoursStart}:00-${s.quietHoursEnd}:00 local)`}),te++}catch(A){console.error("[Broadcast] Failed to defer notification:",A)}}if(h){const q=[...new Set(b.map(v=>v.user_id))];for(const v of q)try{await x.from("notification_history").insert({user_id:v,match_id:h,notification_type:"broadcast",player_names:[],sent_at:new Date().toISOString(),notification_title:d,notification_body:a,is_read:!0})}catch{}}await Xe({action_type:"broadcast",action_category:"notification",target_name:d,details:{filters:s,sent:re,failed:z,deferred:te,skipped_dedup:K,linked_match_id:h,total:b.length}});const Pe=te>0?`, ${te} deferred to morning`:"";F.success(`Broadcast sent to ${re} devices (${z} failed${Pe})`),S(""),m(""),C(null),$("none")}catch(t){console.error("Broadcast error:",t),F.error(t.message||"Failed to send broadcast")}finally{G(!1)}};return e.jsxs("div",{className:"space-y-4",children:[e.jsx(ue,{title:"Venue Notification",icon:We,description:"Send to users at a specific event venue",children:e.jsx(us,{})}),e.jsx("div",{className:"grid grid-cols-1 gap-4",children:e.jsx(ue,{title:"Compose Broadcast",icon:es,description:"Write a push notification to all users",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(_,{className:"text-xs",children:"Title"}),e.jsx(ae,{value:d,onChange:t=>S(t.target.value),placeholder:"Announcement title...",className:"h-9 text-sm",maxLength:50}),e.jsxs("p",{className:"text-[10px] text-muted-foreground text-right",children:[d.length,"/50"]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(_,{className:"text-xs",children:"Message"}),e.jsx(Ne,{value:a,onChange:t=>m(t.target.value),placeholder:"Your message to users...",className:"text-sm min-h-[100px] resize-none",maxLength:200}),e.jsxs("p",{className:"text-[10px] text-muted-foreground text-right",children:[a.length,"/200"]})]}),e.jsx(Ue,{selectedMatchId:h,onSelect:C}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsxs(_,{className:"text-xs flex items-center gap-1",children:[e.jsx(Me,{className:"h-3 w-3"}),"Open Page on Tap"]}),e.jsxs(Z,{value:H,onValueChange:$,children:[e.jsx(J,{className:"h-9 text-sm",children:e.jsx(W,{placeholder:"Default (home)"})}),e.jsxs(ee,{children:[e.jsx(y,{value:"none",children:"Default (home)"}),e.jsx(y,{value:"/pickem",children:"Pick 'Em"}),e.jsx(y,{value:"/stats",children:"Stats & Rankings"}),e.jsx(y,{value:"/schedule",children:"Schedule"}),e.jsx(y,{value:"/notifications",children:"Notifications"}),e.jsx(y,{value:"/players",children:"Players"})]})]}),e.jsx("p",{className:"text-[10px] text-muted-foreground",children:"Page to open when user taps the notification"})]}),e.jsxs("div",{className:"border-t pt-4 space-y-4",children:[e.jsxs("div",{className:"flex items-center gap-2 text-xs font-medium text-muted-foreground",children:[e.jsx(ss,{className:"h-3.5 w-3.5"}),"Audience Filters"]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(_,{className:"text-xs",children:"Platform"}),e.jsx("div",{className:"flex gap-2 flex-wrap",children:["all","ios","android"].map(t=>e.jsx(Q,{variant:s.platform===t?"default":"outline",size:"sm",onClick:()=>c(n=>({...n,platform:t})),className:"text-xs",children:t==="all"?"All Platforms":t.toUpperCase()},t))})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(_,{className:"text-xs",children:"User Activity"}),e.jsx("div",{className:"flex gap-2 flex-wrap",children:[{value:null,label:"All Users"},{value:7,label:"Active (7 days)"},{value:30,label:"Active (30 days)"},{value:90,label:"Active (90 days)"}].map(t=>e.jsx(Q,{variant:s.activeInDays===t.value?"default":"outline",size:"sm",onClick:()=>c(n=>({...n,activeInDays:t.value})),className:"text-xs",children:t.label},t.value??"all"))})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(de,{id:"followedPlayers",checked:s.hasFollowedPlayers===!0,onCheckedChange:t=>c(n=>({...n,hasFollowedPlayers:t?!0:null}))}),e.jsx(_,{htmlFor:"followedPlayers",className:"text-xs cursor-pointer",children:"Only users following players"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(de,{id:"excludeRecent",checked:s.excludeRecentBroadcast,onCheckedChange:t=>c(n=>({...n,excludeRecentBroadcast:t===!0}))}),e.jsx(_,{htmlFor:"excludeRecent",className:"text-xs cursor-pointer",children:"Exclude users who received broadcast recently"})]}),s.excludeRecentBroadcast&&e.jsxs("div",{className:"ml-6 flex items-center gap-2",children:[e.jsx(_,{className:"text-xs text-muted-foreground whitespace-nowrap",children:"Cooldown:"}),e.jsxs(Z,{value:String(s.excludeRecentHours),onValueChange:t=>c(n=>({...n,excludeRecentHours:Number(t)})),children:[e.jsx(J,{className:"h-7 text-xs w-[140px]",children:e.jsx(W,{})}),e.jsxs(ee,{children:[e.jsx(y,{value:"1",children:"1 hour"}),e.jsx(y,{value:"2",children:"2 hours"}),e.jsx(y,{value:"4",children:"4 hours"}),e.jsx(y,{value:"6",children:"6 hours"}),e.jsx(y,{value:"12",children:"12 hours"}),e.jsx(y,{value:"24",children:"24 hours"}),e.jsx(y,{value:"48",children:"48 hours"}),e.jsx(y,{value:"72",children:"72 hours"})]})]})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(de,{id:"quietHours",checked:s.quietHoursEnabled,onCheckedChange:t=>c(n=>({...n,quietHoursEnabled:t===!0}))}),e.jsx(_,{htmlFor:"quietHours",className:"text-xs cursor-pointer",children:"Respect user local quiet hours (defer if outside window)"})]}),s.quietHoursEnabled&&e.jsxs("div",{className:"ml-6 space-y-2 p-2.5 bg-muted/50 rounded-lg border",children:[e.jsx("p",{className:"text-[10px] text-muted-foreground",children:"Only send immediately to users whose local time is within this window. Others will receive the notification when they exit quiet hours."}),e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[e.jsx(_,{className:"text-xs text-muted-foreground whitespace-nowrap",children:"Send between"}),e.jsxs(Z,{value:String(s.quietHoursEnd),onValueChange:t=>c(n=>({...n,quietHoursEnd:Number(t)})),children:[e.jsx(J,{className:"h-7 text-xs w-[100px]",children:e.jsx(W,{})}),e.jsx(ee,{children:[5,6,7,8,9,10,11,12].map(t=>e.jsxs(y,{value:String(t),children:[t,":00 AM"]},t))})]}),e.jsx("span",{className:"text-xs text-muted-foreground",children:"and"}),e.jsxs(Z,{value:String(s.quietHoursStart),onValueChange:t=>c(n=>({...n,quietHoursStart:Number(t)})),children:[e.jsx(J,{className:"h-7 text-xs w-[100px]",children:e.jsx(W,{})}),e.jsx(ee,{children:[18,19,20,21,22,23].map(t=>e.jsxs(y,{value:String(t),children:[t>12?t-12:t,":00 PM"]},t))})]}),e.jsx("span",{className:"text-[10px] text-muted-foreground",children:"(user's local time)"})]})]})]}),e.jsx("div",{className:"p-3 bg-muted/50 rounded-lg border",children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-xs text-muted-foreground",children:"Estimated Recipients"}),e.jsx(U,{variant:"secondary",className:"text-sm font-semibold",children:I?"...":(p==null?void 0:p.toLocaleStr
1ing())??0})]})})]})]})})}),e.jsx("div",{className:"flex flex-col items-end gap-1",children:e.jsxs("div",{className:"flex gap-2",children:[e.jsxs("div",{className:"flex flex-col items-center",children:[e.jsx(Q,{variant:"outline",onClick:R,disabled:o||V||!d.trim()||!a.trim(),children:o?e.jsxs(e.Fragment,{children:[e.jsx(me,{className:"h-4 w-4 mr-2 animate-spin"}),"Sending..."]}):e.jsxs(e.Fragment,{children:[e.jsx(ts,{className:"h-4 w-4 mr-2"}),"Send Test"]})}),e.jsx("span",{className:"text-[10px] text-muted-foreground mt-0.5",children:"Your device only"})]}),e.jsx(Q,{onClick:E,disabled:V||!d.trim()||!a.trim()||p===0,size:"lg",className:"min-w-[200px]",children:V?e.jsxs(e.Fragment,{children:[e.jsx(me,{className:"h-4 w-4 mr-2 animate-spin"}),"Sending..."]}):e.jsxs(e.Fragment,{children:[e.jsx(ve,{className:"h-4 w-4 mr-2"}),"Preview & Send"]})})]})}),e.jsx(ue,{title:"Broadcast History",icon:ge,headerAction:e.jsx(Q,{variant:"ghost",size:"sm",onClick:()=>ce(),className:"h-7 w-7 p-0",children:e.jsx(is,{className:"h-3.5 w-3.5"})}),children:le?e.jsx("div",{className:"space-y-2",children:[1,2,3].map(t=>e.jsxs("div",{className:"p-3 bg-muted/50 rounded-lg animate-pulse",children:[e.jsx("div",{className:"h-4 w-3/4 bg-muted rounded mb-2"}),e.jsx("div",{className:"h-3 w-1/2 bg-muted rounded"})]},t))}):ie.length===0?e.jsxs("div",{className:"text-center py-8 text-muted-foreground",children:[e.jsx(ge,{className:"h-8 w-8 mx-auto mb-2 opacity-50"}),e.jsx("p",{className:"text-sm",children:"No broadcasts sent yet"})]}):e.jsx("div",{className:"space-y-2 max-h-[300px] overflow-y-auto",children:ie.map(t=>{var M,b;const n=t.details,T=n!=null&&n.total&&n.total>0?Math.round((n.sent||0)/n.total*100):0;return e.jsxs("div",{className:"p-3 rounded-lg border bg-muted/30 space-y-2",children:[e.jsxs("div",{className:"flex items-start justify-between gap-2",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"text-sm font-medium truncate",children:t.target_name||"Untitled"}),e.jsxs("p",{className:"text-[10px] text-muted-foreground",children:[(M=t.admin_email)==null?void 0:M.split("@")[0]," • ",Oe(new Date(t.created_at),{addSuffix:!0})]})]}),e.jsx("div",{className:"flex items-center gap-1.5 shrink-0",children:e.jsxs(U,{variant:T>=90?"default":T>=70?"secondary":"destructive",className:"text-[10px]",children:[T,"% success"]})})]}),e.jsxs("div",{className:"flex items-center gap-3 text-[10px] text-muted-foreground",children:[e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx(xe,{className:"h-3 w-3"}),(n==null?void 0:n.total)||0," recipients"]}),e.jsxs("span",{className:"flex items-center gap-1 text-green-600 dark:text-green-400",children:[e.jsx(as,{className:"h-3 w-3"}),(n==null?void 0:n.sent)||0," sent"]}),((n==null?void 0:n.failed)||0)>0&&e.jsxs("span",{className:"flex items-center gap-1 text-destructive",children:[e.jsx(ns,{className:"h-3 w-3"}),n.failed," failed"]}),((n==null?void 0:n.deferred)||0)>0&&e.jsxs("span",{className:"flex items-center gap-1 text-muted-foreground",children:[e.jsx(je,{className:"h-3 w-3"}),n.deferred," deferred"]}),((b=n==null?void 0:n.filters)==null?void 0:b.platform)&&n.filters.platform!=="all"&&e.jsx(U,{variant:"outline",className:"text-[9px] px-1",children:n.filters.platform.toUpperCase()})]})]},t.id)})})}),e.jsx(cs,{}),e.jsx(_e,{open:L,onOpenChange:D,children:e.jsxs(be,{className:"max-w-md",children:[e.jsxs(ke,{children:[e.jsxs(Se,{className:"flex items-center gap-2 text-base",children:[e.jsx(Ae,{className:"h-4 w-4 text-amber-500"}),"Review Broadcast"]}),e.jsx(Ce,{asChild:!0,children:e.jsxs("div",{className:"text-sm space-y-3",children:[e.jsxs("div",{className:"p-3 bg-muted rounded-lg space-y-1",children:[e.jsx("p",{className:"font-medium text-foreground",children:d}),e.jsx("p",{className:"text-xs text-muted-foreground",children:a})]}),e.jsxs("div",{className:"space-y-2 text-xs",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{children:"Platform:"}),e.jsx(U,{variant:"outline",children:s.platform==="all"?"All":s.platform.toUpperCase()})]}),s.activeInDays&&e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{children:"Activity filter:"}),e.jsxs(U,{variant:"outline",children:["Active in ",s.activeInDays," days"]})]}),s.hasFollowedPlayers&&e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{children:"Following players:"}),e.jsx(U,{variant:"outline",children:"Yes"})]}),s.excludeRecentBroadcast&&e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{children:"Exclude recent:"}),e.jsxs(U,{variant:"outline",children:["Last ",s.excludeRecentHours,"h"]})]}),s.quietHoursEnabled&&e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{children:"Qu
1iet hours:"}),e.jsxs(U,{variant:"outline",className:"flex items-center gap-1",children:[e.jsx(je,{className:"h-3 w-3"}),"Send ",s.quietHoursEnd,":00–",s.quietHoursStart,":00 local"]})]}),e.jsxs("div",{className:"flex items-center justify-between pt-2 border-t",children:[e.jsx("span",{className:"font-medium",children:"Recipients:"}),e.jsxs(U,{variant:"secondary",className:"flex items-center gap-1",children:[e.jsx(xe,{className:"h-3 w-3"}),p==null?void 0:p.toLocaleString()]})]}),s.quietHoursEnabled&&e.jsxs("p",{className:"text-[10px] text-muted-foreground pt-1",children:["Users outside the send window will receive the notification when their local time reaches ",s.quietHoursEnd,":00 AM."]})]})]})})]}),e.jsxs(De,{children:[e.jsx(Ee,{className:"text-sm",children:"Cancel"}),e.jsx(qe,{onClick:()=>{D(!1),l(!0)},className:"text-sm",children:"Continue"})]})]})}),e.jsx(_e,{open:i,onOpenChange:l,children:e.jsxs(be,{className:"max-w-sm",children:[e.jsxs(ke,{children:[e.jsxs(Se,{className:"flex items-center gap-2 text-base text-destructive",children:[e.jsx(Ae,{className:"h-5 w-5"}),"Are you absolutely sure?"]}),e.jsxs(Ce,{className:"text-sm",children:["This will send a push notification to ",e.jsx("strong",{className:"text-foreground",children:p==null?void 0:p.toLocaleString()})," users",s.quietHoursEnabled?" (users in quiet hours will be deferred)":" immediately",".",e.jsx("span",{className:"block mt-2 text-destructive font-medium",children:"This action cannot be undone."})]})]}),e.jsxs(De,{children:[e.jsx(Ee,{className:"text-sm",children:"Go Back"}),e.jsxs(qe,{onClick:Y,className:"text-sm bg-destructive text-destructive-foreground hover:bg-destructive/90",children:[e.jsx(ve,{className:"h-3.5 w-3.5 mr-1.5"}),"Yes, Send Now"]})]})]})})]})});export{Ss as BroadcastsTab};

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.