"use client" ;
import { useState } from "react" ;
import {
Sparkles,
Mail,
Check,
Trophy,
Users,
Share2,
Twitter,
Copy,
ArrowUp,
} from "lucide-react" ;
import { Button } from "@/components/ui/button" ;
import { Badge } from "@/components/ui/badge" ;
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog" ;
import { Input } from "@/components/ui/input" ;
import { Progress } from "@/components/ui/progress" ;
import { Separator } from "@/components/ui/separator" ;
import { cn } from "@/lib/utils" ;
export const title = "React Dialog Block Waitlist Signup" ;
export default function DialogWaitlistSignup () {
const [ open , setOpen ] = useState ( false );
const [ email , setEmail ] = useState ( "" );
const [ joined , setJoined ] = useState ( false );
const [ copied , setCopied ] = useState ( false );
const waitlistData = {
position: 1247 ,
total: 8500 ,
referrals: 3 ,
positionGain: 156 ,
referralLink: "https://app.example.com/waitlist?ref=abc123" ,
};
const percentile = Math. round (( 1 - waitlistData.position / waitlistData.total) * 100 );
const handleJoin = () => {
if ( ! email) return ;
console. log ( "Joining waitlist:" , email);
setJoined ( true );
};
const handleCopyLink = () => {
navigator.clipboard. writeText (waitlistData.referralLink);
setCopied ( true );
setTimeout (() => setCopied ( false ), 2000 );
};
const handleShare = ( platform : string ) => {
const text = "I just joined the waitlist for this amazing new product! Join me:" ;
const url = waitlistData.referralLink;
if (platform === "twitter" ) {
window. open (
`https://twitter.com/intent/tweet?text=${ encodeURIComponent ( text ) }&url=${ encodeURIComponent ( url ) }` ,
"_blank"
);
}
};
const handleClose = () => {
setOpen ( false );
setTimeout (() => {
setEmail ( "" );
setJoined ( false );
setCopied ( false );
}, 200 );
};
const isValidEmail = email. includes ( "@" ) && email. includes ( "." );
return (
< Dialog open = {open} onOpenChange = {setOpen}>
< div className = "flex min-h-[350px] items-center justify-center" >
< DialogTrigger asChild >
< Button variant = "outline" >
< Sparkles className = "mr-2 h-4 w-4" />
Join Waitlist
</ Button >
</ DialogTrigger >
</ div >
< DialogContent className = "sm:max-w-sm" >
{ ! joined ? (
<>
< DialogHeader className = "text-center" >
< div className = "mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-primary/10 mb-2" >
< Sparkles className = "h-6 w-6 text-primary" />
</ div >
< DialogTitle >Get Early Access</ DialogTitle >
< DialogDescription >
Join {waitlistData.total. toLocaleString ()}+ others waiting for launch.
</ DialogDescription >
</ DialogHeader >
< div className = "space-y-4 py-4" >
< div className = "space-y-2" >
< div className = "relative" >
< Mail className = "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
< Input
type = "email"
placeholder = "Enter your email"
value = {email}
onChange = {( e ) => setEmail (e.target.value)}
className = "pl-9"
/>
</ div >
</ div >
< Button
onClick = {handleJoin}
disabled = { ! isValidEmail}
className = "w-full"
>
Join the Waitlist
</ Button >
< p className = "text-xs text-center text-muted-foreground" >
We'll notify you when it's your turn. No spam, ever.
</ p >
</ div >
</>
) : (
<>
< DialogHeader className = "text-center" >
< div className = "mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-primary/10 mb-2" >
< Check className = "h-6 w-6 text-primary" />
</ div >
< DialogTitle >You're on the list!</ DialogTitle >
< DialogDescription >
We'll email you when it's your turn.
</ DialogDescription >
</ DialogHeader >
< div className = "space-y-4 py-4" >
< div className = "rounded-lg border bg-muted/30 p-4 text-center" >
< p className = "text-sm text-muted-foreground mb-1" >Your position</ p >
< p className = "text-4xl font-bold" >#{waitlistData.position. toLocaleString ()}</ p >
< div className = "flex items-center justify-center gap-1 mt-1" >
< Badge variant = "secondary" className = "text-xs" >
Top {percentile}%
</ Badge >
{waitlistData.positionGain > 0 && (
< Badge className = "text-xs bg-primary/10 text-primary hover:bg-primary/20" >
< ArrowUp className = "h-3 w-3 mr-0.5" />
{waitlistData.positionGain} spots
</ Badge >
)}
</ div >
</ div >
< div className = "space-y-2" >
< div className = "flex justify-between text-sm" >
< span className = "text-muted-foreground" >Progress to launch</ span >
< span className = "font-medium" >{percentile}%</ span >
</ div >
< Progress value = {percentile} className = "h-2" />
</ div >
< Separator />
< div className = "space-y-3" >
< div className = "flex items-center justify-between" >
< p className = "text-sm font-medium" >Move up faster</ p >
< div className = "flex items-center gap-1 text-xs text-muted-foreground" >
< Users className = "h-3 w-3" />
{waitlistData.referrals} referrals
</ div >
</ div >
< p className = "text-xs text-muted-foreground" >
Each friend who joins moves you up 50 spots!
</ p >
< div className = "flex gap-2" >
< Input
value = {waitlistData.referralLink}
readOnly
className = "text-xs bg-muted/50"
/>
< Button
variant = "outline"
size = "icon"
onClick = {handleCopyLink}
className = "shrink-0"
>
{copied ? (
< Check className = "h-4 w-4 text-primary" />
) : (
< Copy className = "h-4 w-4" />
)}
</ Button >
</ div >
< div className = "flex gap-2" >
< Button
variant = "outline"
className = "flex-1"
onClick = {() => handleShare ( "twitter" )}
>
< Twitter className = "mr-2 h-4 w-4" />
Share
</ Button >
< Button
variant = "outline"
className = "flex-1"
onClick = {handleCopyLink}
>
< Share2 className = "mr-2 h-4 w-4" />
Copy Link
</ Button >
</ div >
</ div >
< div className = "rounded-lg border p-3 bg-primary/5 border-primary/20" >
< div className = "flex items-start gap-2" >
< Trophy className = "h-4 w-4 text-primary mt-0.5" />
< div >
< p className = "text-sm font-medium" >Refer 5 friends</ p >
< p className = "text-xs text-muted-foreground" >
Get guaranteed access in the first wave
</ p >
</ div >
</ div >
</ div >
</ div >
</>
)}
</ DialogContent >
</ Dialog >
);
}