@@ -11,6 +11,7 @@ import { associateUserWithTenant } from "@/lib/membership-service";
1111import { useTranslation } from "react-i18next" ;
1212import { AuthFlowStep } from "@/hooks/useTenantAuthFlow" ;
1313import { useToast } from "@/hooks/use-toast" ;
14+ import { useInvalidateTenants } from "@/hooks/useTenants" ;
1415
1516export default function AuthPage ( ) {
1617 const { slug } = useParams < { slug : string } > ( ) ;
@@ -26,6 +27,7 @@ export default function AuthPage() {
2627 const [ hasAttemptedAssociation , setHasAttemptedAssociation ] = useState ( false ) ;
2728 const { t } = useTranslation ( ) ;
2829 const { toast } = useToast ( ) ;
30+ const invalidateTenants = useInvalidateTenants ( ) ;
2931
3032 // Get the flow step from URL query parameter
3133 const flowStep = searchParams . get ( "flow" ) as AuthFlowStep | null ;
@@ -81,6 +83,7 @@ export default function AuthPage() {
8183 try {
8284 await associateUserWithTenant ( user . id , tenant . id ) ;
8385 setHasAttemptedAssociation ( true ) ;
86+ invalidateTenants ( ) ;
8487
8588 toast ( {
8689 title : t ( "auth:joinedChurch" ) ,
@@ -106,13 +109,32 @@ export default function AuthPage() {
106109 hasAttemptedAssociation ,
107110 t ,
108111 toast ,
112+ invalidateTenants ,
109113 ] ) ;
110114
111115 useEffect ( ( ) => {
112116 const checkUserMembership = async ( ) => {
113117 if ( ! isLoading && user && tenant && slug ) {
114118 try {
115- const hasAccess = await checkUserTenantAccess ( user . id , slug ) ;
119+ const isJoinFlow = flowStep === "signup" || flowStep === "join-signin" ;
120+
121+ // Prevent premature "no permission" during OAuth auto-join
122+ if ( ! inviteToken && isJoinFlow ) {
123+ if ( isAssociating ) return ;
124+ // Wait for the auto-join attempt to complete before deciding access
125+ if ( ! hasAttemptedAssociation ) return ;
126+ }
127+
128+ // Optional reliability: retry a few times after join attempt to smooth out timing
129+ let hasAccess = false ;
130+ const maxAttempts = ! inviteToken && isJoinFlow && hasAttemptedAssociation ? 5 : 1 ;
131+ for ( let attempt = 0 ; attempt < maxAttempts ; attempt ++ ) {
132+ hasAccess = await checkUserTenantAccess ( user . id , slug ) ;
133+ if ( hasAccess ) break ;
134+ if ( attempt < maxAttempts - 1 ) {
135+ await new Promise ( ( resolve ) => setTimeout ( resolve , 250 ) ) ;
136+ }
137+ }
116138
117139 if ( hasAccess ) {
118140 // Redirect to original page if specified
@@ -121,7 +143,7 @@ export default function AuthPage() {
121143 } else {
122144 navigate ( `/tenant/${ slug } ` ) ;
123145 }
124- } else if ( ! inviteToken ) {
146+ } else if ( ! inviteToken && ! ( isJoinFlow && ! hasAttemptedAssociation ) ) {
125147 // ADD: User-facing error message instead of console.log
126148 setError ( t ( "auth:noPermissionToEnterChurch" ) ) ;
127149 toast ( {
@@ -137,7 +159,20 @@ export default function AuthPage() {
137159 } ;
138160
139161 checkUserMembership ( ) ;
140- } , [ user , isLoading , navigate , tenant , slug , inviteToken , redirectTo , t , toast ] ) ;
162+ } , [
163+ user ,
164+ isLoading ,
165+ navigate ,
166+ tenant ,
167+ slug ,
168+ inviteToken ,
169+ redirectTo ,
170+ t ,
171+ toast ,
172+ flowStep ,
173+ isAssociating ,
174+ hasAttemptedAssociation ,
175+ ] ) ;
141176
142177 const handleAuthSuccess = ( ) => {
143178 // If redirect parameter exists and is a valid tenant path, use it
0 commit comments