import 'package:flutter/material.dart'; import 'package:supabase_flutter/supabase_flutter.dart'; import 'package:tugas_akhir_supabase/services/session_manager.dart'; import 'package:tugas_akhir_supabase/widgets/session_expired_dialog.dart'; /// A widget that enforces session validation for authenticated routes. /// /// This widget should wrap any screen that requires authentication. /// It will automatically check if the session is valid and redirect to login /// if the session has expired. class SessionGuardWrapper extends StatefulWidget { final Widget child; final bool enforceAuthentication; const SessionGuardWrapper({ super.key, required this.child, this.enforceAuthentication = true, }); @override State createState() => _SessionGuardWrapperState(); } class _SessionGuardWrapperState extends State { bool _isCheckingSession = false; bool _sessionExpired = false; bool _showingDialog = false; bool _hasInitialized = false; @override void initState() { super.initState(); // Initialize with a delay to prevent race conditions WidgetsBinding.instance.addPostFrameCallback((_) { if (mounted && !_hasInitialized) { _hasInitialized = true; // Check session on widget initialization if (widget.enforceAuthentication) { _checkSession(); } } }); // Tambahkan listener untuk dismiss dialog jika user login/logout Supabase.instance.client.auth.onAuthStateChange.listen((event) { final currentUser = Supabase.instance.client.auth.currentUser; if (currentUser != null) { setState(() { _sessionExpired = false; _showingDialog = false; }); // Pop dialog jika masih terbuka if (Navigator.canPop(context)) { Navigator.of( context, rootNavigator: true, ).popUntil((route) => route.isFirst); } } }); } @override void didChangeDependencies() { super.didChangeDependencies(); // Check session when dependencies change (e.g., after navigation) // But only if we haven't initialized yet or if there's a significant change if (widget.enforceAuthentication && !_isCheckingSession && _hasInitialized) { // Add a small delay to prevent race conditions during navigation Future.delayed(const Duration(milliseconds: 100), () { if (mounted) { _checkSession(); } }); } } Future _checkSession() async { // Session checking DISABLED for permissive mode debugPrint('SessionGuard: Session checking DISABLED for permissive mode'); return; } void _showExpiredDialog() { if (_showingDialog) return; // Double check if user is actually logged in before showing dialog final currentUser = Supabase.instance.client.auth.currentUser; final currentSession = Supabase.instance.client.auth.currentSession; if (currentUser == null || currentSession == null) { debugPrint( 'SessionGuard: No user or session, not showing expired dialog', ); _showingDialog = false; return; } debugPrint( 'SessionGuard: Showing expired dialog for user: ${currentUser.id}', ); _showingDialog = true; // Show dialog on next frame to avoid build phase issues WidgetsBinding.instance.addPostFrameCallback((_) { if (!mounted) { _showingDialog = false; return; } // Final check before showing dialog final finalUser = Supabase.instance.client.auth.currentUser; if (finalUser == null) { debugPrint('SessionGuard: User logged out before showing dialog'); _showingDialog = false; return; } showDialog( context: context, barrierDismissible: false, builder: (context) => const SessionExpiredDialog(), ).then((_) { _showingDialog = false; }); }); } @override Widget build(BuildContext context) { debugPrint('SessionGuard: build called - PERMISSIVE MODE'); // PERMISSIVE MODE - Always show the child without any restrictions debugPrint( 'SessionGuard: Showing child widget without session restrictions', ); return widget.child; } }