22import { useEffect , useState , useCallback , useRef } from "react" ;
33import { useParams } from "next/navigation" ;
44import { copyText } from "@/lib/clipboard" ;
5- import { filterSignupsByStatus , type WaitlistStatus } from "@/lib/waitlist-filter" ;
5+ import {
6+ filterSignupsByQuery ,
7+ filterSignupsByStatus ,
8+ type WaitlistStatus ,
9+ } from "@/lib/waitlist-filter" ;
610import MoshpitTlds from "@/components/MoshpitTlds" ;
711
812// Tab values double as URL slugs: /dashboard/<tab> (the default "page" tab lives at
@@ -759,6 +763,7 @@ function WaitlistPanel({ onError }: { onError: (m: string) => void }) {
759763 const [ active , setActive ] = useState < string | null > ( null ) ;
760764 const [ signups , setSignups ] = useState < any [ ] | null > ( null ) ;
761765 const [ status , setStatus ] = useState < WaitlistStatus > ( "all" ) ;
766+ const [ query , setQuery ] = useState ( "" ) ;
762767
763768 const load = async ( dn : string ) => {
764769 setActive ( dn ) ; setSignups ( null ) ;
@@ -783,11 +788,15 @@ function WaitlistPanel({ onError }: { onError: (m: string) => void }) {
783788 return < section className = "card2" > < h2 > Waitlist</ h2 > < p className = "sub" > No parked domains yet — claim one on the “Domains” tab and its waitlist shows up here.</ p > </ section > ;
784789 }
785790
786- const filtered = signups ? filterSignupsByStatus ( signups , status ) : null ;
787- const verifiedCount = signups ?. filter ( ( signup ) => signup . verified ) . length ?? 0 ;
788- const pendingCount = signups ? signups . length - verifiedCount : 0 ;
791+ const matchingSignups = signups ? filterSignupsByQuery ( signups , query ) : null ;
792+ const filtered = matchingSignups
793+ ? filterSignupsByStatus ( matchingSignups , status )
794+ : null ;
795+ const hasFilters = status !== "all" || query . trim ( ) !== "" ;
796+ const verifiedCount = matchingSignups ?. filter ( ( signup ) => signup . verified ) . length ?? 0 ;
797+ const pendingCount = matchingSignups ? matchingSignups . length - verifiedCount : 0 ;
789798 const filters : { value : WaitlistStatus ; label : string ; count : number } [ ] = [
790- { value : "all" , label : "All" , count : signups ?. length ?? 0 } ,
799+ { value : "all" , label : "All" , count : matchingSignups ?. length ?? 0 } ,
791800 { value : "verified" , label : "Confirmed" , count : verifiedCount } ,
792801 { value : "pending" , label : "Pending" , count : pendingCount } ,
793802 ] ;
@@ -807,10 +816,25 @@ function WaitlistPanel({ onError }: { onError: (m: string) => void }) {
807816 < >
808817 < div className = "row" style = { { justifyContent : "space-between" , alignItems : "center" } } >
809818 < h3 className = "ed-h" > { active } — { filtered ? filtered . length : "…" } signups</ h3 >
810- < a className = "btn2 ghost" href = { `/api/waitlist/manage?dn=${ encodeURIComponent ( active ) } &format=csv&status=${ status } ` } >
811- { status === "all" ? "Export CSV" : "Export filtered CSV" }
819+ < a className = "btn2 ghost" href = { `/api/waitlist/manage?dn=${ encodeURIComponent ( active ) } &format=csv&status=${ status } &q= ${ encodeURIComponent ( query ) } ` } >
820+ { hasFilters ? "Export filtered CSV" : "Export CSV" }
812821 </ a >
813822 </ div >
823+ < div className = "row" style = { { alignItems : "center" } } >
824+ < input
825+ className = "inp"
826+ type = "search"
827+ value = { query }
828+ onChange = { ( event ) => setQuery ( event . target . value ) }
829+ placeholder = "Search by email or referral code"
830+ aria-label = "Search waitlist signups"
831+ />
832+ { query && (
833+ < button className = "btn2 ghost" type = "button" onClick = { ( ) => setQuery ( "" ) } >
834+ Clear
835+ </ button >
836+ ) }
837+ </ div >
814838 < div className = "tabs" role = "group" aria-label = "Filter waitlist signups" >
815839 { filters . map ( ( filter ) => (
816840 < button
@@ -828,7 +852,11 @@ function WaitlistPanel({ onError }: { onError: (m: string) => void }) {
828852 { signups === null && < li className = "muted" > Loading…</ li > }
829853 { filtered && filtered . length === 0 && (
830854 < li className = "muted" >
831- { signups ?. length ? `No ${ status === "verified" ? "confirmed" : status } signups.` : "No signups yet — share your page." }
855+ { signups ?. length
856+ ? hasFilters
857+ ? "No signups match the current filters."
858+ : "No signups found."
859+ : "No signups yet — share your page." }
832860 </ li >
833861 ) }
834862 { filtered && filtered . map ( ( s ) => (
0 commit comments