11"use client" ;
22
33import React , { useState , useEffect } from "react" ;
4+ import { createPortal } from "react-dom" ;
45import { useAuth } from "../contexts/AuthContext" ;
56import { Button } from "./Button" ;
67
@@ -34,6 +35,20 @@ export const AuthModal: React.FC<AuthModalProps> = ({
3435 type : string ;
3536 value : string ;
3637 } | null > ( null ) ;
38+ const [ mounted , setMounted ] = useState ( false ) ;
39+
40+ useEffect ( ( ) => {
41+ setMounted ( true ) ;
42+ } , [ ] ) ;
43+
44+ useEffect ( ( ) => {
45+ if ( ! isOpen ) return ;
46+ const previousOverflow = document . body . style . overflow ;
47+ document . body . style . overflow = "hidden" ;
48+ return ( ) => {
49+ document . body . style . overflow = previousOverflow ;
50+ } ;
51+ } , [ isOpen ] ) ;
3752
3853 // Load last used method from localStorage
3954 useEffect ( ( ) => {
@@ -67,7 +82,7 @@ export const AuthModal: React.FC<AuthModalProps> = ({
6782 }
6883 } , [ isAuthenticated , isOpen , onClose ] ) ;
6984
70- if ( ! isOpen ) return null ;
85+ if ( ! isOpen || ! mounted ) return null ;
7186
7287 const handleEmailSignIn = async ( e : React . FormEvent ) => {
7388 e . preventDefault ( ) ;
@@ -155,13 +170,30 @@ export const AuthModal: React.FC<AuthModalProps> = ({
155170 }
156171 } ;
157172
158- return (
159- < div className = "fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4" >
160- < div className = "bg-slate-800 rounded-lg p-6 w-full max-w-md" >
173+ return createPortal (
174+ < div
175+ className = "fixed inset-0 z-[100] flex min-h-[100dvh] items-center justify-center overflow-y-auto bg-black/50 px-4 py-6 sm:py-10"
176+ style = { {
177+ paddingTop : "max(1.5rem, env(safe-area-inset-top))" ,
178+ paddingBottom : "max(1.5rem, env(safe-area-inset-bottom))" ,
179+ } }
180+ role = "presentation"
181+ onClick = { onClose }
182+ >
183+ < div
184+ className = "relative w-full max-w-md shrink-0 rounded-lg bg-slate-800 p-6 shadow-2xl"
185+ role = "dialog"
186+ aria-modal = "true"
187+ aria-labelledby = "auth-modal-title"
188+ onClick = { ( e ) => e . stopPropagation ( ) }
189+ >
161190 < div className = "text-center mb-6" >
162191 { trialExpired ? (
163192 < >
164- < h2 className = "text-2xl font-bold text-white mb-2" >
193+ < h2
194+ id = "auth-modal-title"
195+ className = "text-2xl font-bold text-white mb-2"
196+ >
165197 Trial Expired
166198 </ h2 >
167199 < p className = "text-slate-300" >
@@ -171,7 +203,12 @@ export const AuthModal: React.FC<AuthModalProps> = ({
171203 </ >
172204 ) : (
173205 < >
174- < h2 className = "text-2xl font-bold text-white mb-2" > Sign In</ h2 >
206+ < h2
207+ id = "auth-modal-title"
208+ className = "text-2xl font-bold text-white mb-2"
209+ >
210+ Sign In
211+ </ h2 >
175212 < p className = "text-slate-300" >
176213 Choose your preferred sign-in method to continue.
177214 </ p >
@@ -325,8 +362,8 @@ export const AuthModal: React.FC<AuthModalProps> = ({
325362 { isVerifying
326363 ? "Verifying..."
327364 : isRedirecting
328- ? "Redirecting..."
329- : "Verify Code" }
365+ ? "Redirecting..."
366+ : "Verify Code" }
330367 </ Button >
331368 </ form >
332369
@@ -437,6 +474,7 @@ export const AuthModal: React.FC<AuthModalProps> = ({
437474 </ button >
438475 </ div >
439476 </ div >
440- </ div >
477+ </ div > ,
478+ document . body ,
441479 ) ;
442480} ;
0 commit comments