From 3eb7ed01eed912e7cbbf2229409670c36f6dead6 Mon Sep 17 00:00:00 2001 From: kyy Date: Thu, 19 Feb 2026 16:08:42 +0900 Subject: [PATCH] =?UTF-8?q?flutter=20=EB=A6=B0=ED=8A=B8=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- userfront/lib/core/i18n/locale_utils.dart | 13 ++++++++ .../core/services/auth_token_store_web.dart | 2 +- .../lib/core/services/web_window_web.dart | 10 +----- .../lib/core/widgets/language_selector.dart | 5 ++- .../auth/presentation/login_screen.dart | 32 ++----------------- .../auth/presentation/signup_screen.dart | 6 ++-- userfront/lib/main.dart | 22 ++----------- userfront/test/helpers/web_storage_web.dart | 18 +++++------ 8 files changed, 35 insertions(+), 73 deletions(-) diff --git a/userfront/lib/core/i18n/locale_utils.dart b/userfront/lib/core/i18n/locale_utils.dart index 9b942f7d..926524e8 100644 --- a/userfront/lib/core/i18n/locale_utils.dart +++ b/userfront/lib/core/i18n/locale_utils.dart @@ -88,3 +88,16 @@ String buildLocalizedPath(String localeCode, Uri uri) { } return result; } + +String buildSigninRedirectPath(String localeCode, Uri uri) { + final newPath = '/$localeCode/signin'; + final newUri = uri.replace(path: newPath); + String result = newUri.path; + if (newUri.hasQuery) { + result += '?${newUri.query}'; + } + if (newUri.hasFragment) { + result += '#${newUri.fragment}'; + } + return result; +} diff --git a/userfront/lib/core/services/auth_token_store_web.dart b/userfront/lib/core/services/auth_token_store_web.dart index 9e076351..0f828e7a 100644 --- a/userfront/lib/core/services/auth_token_store_web.dart +++ b/userfront/lib/core/services/auth_token_store_web.dart @@ -50,7 +50,7 @@ class AuthTokenStore { _localStorage.setItem(_providerKey, provider); } } catch (e) { - print("[AuthTokenStore] CRITICAL - Failed to set token: $e"); + // ignore } } diff --git a/userfront/lib/core/services/web_window_web.dart b/userfront/lib/core/services/web_window_web.dart index 6fafbf6f..ed147e85 100644 --- a/userfront/lib/core/services/web_window_web.dart +++ b/userfront/lib/core/services/web_window_web.dart @@ -12,25 +12,17 @@ class WebWindow { void redirectTo(String url) { final currentHref = web.window.location.href; - Uri? targetUri; - try { - targetUri = Uri.parse(url); - } catch (_) { - debugPrint("[WebWindow] redirectTo parse failed: url=$url"); - } debugPrint( "[WebWindow] redirectTo start: current=$currentHref, target=$url", ); - print("[WebWindow] FINAL REDIRECT ATTEMPT. URL: $url"); - // Most direct and safe way for WASM: location.href assignment via package:web Future.delayed(Duration.zero, () { try { web.window.location.href = url; } catch (e) { - print("[WebWindow] CRITICAL JS ERROR: $e"); + debugPrint("[WebWindow] CRITICAL JS ERROR: $e"); } }); diff --git a/userfront/lib/core/widgets/language_selector.dart b/userfront/lib/core/widgets/language_selector.dart index 3300ab79..8649e403 100644 --- a/userfront/lib/core/widgets/language_selector.dart +++ b/userfront/lib/core/widgets/language_selector.dart @@ -38,11 +38,10 @@ class LanguageSelector extends StatelessWidget { } LocaleStorage.write(value); await context.setLocale(Locale(value)); + if (!context.mounted) return; final uri = GoRouterState.of(context).uri; final target = buildLocalizedPath(value, uri); - if (context.mounted) { - context.go(target); - } + context.go(target); }, ), ); diff --git a/userfront/lib/features/auth/presentation/login_screen.dart b/userfront/lib/features/auth/presentation/login_screen.dart index 93ac1b0c..20e4b4ba 100644 --- a/userfront/lib/features/auth/presentation/login_screen.dart +++ b/userfront/lib/features/auth/presentation/login_screen.dart @@ -12,7 +12,6 @@ import '../../../core/services/auth_token_store.dart'; import '../../../core/services/oidc_redirect_guard.dart'; import '../../../core/notifiers/auth_notifier.dart'; import '../domain/login_challenge_resolver.dart'; -import '../domain/password_login_flow_policy.dart'; import '../../profile/domain/notifiers/profile_notifier.dart'; import '../../../core/services/web_window.dart'; @@ -742,7 +741,6 @@ class _LoginScreenState extends ConsumerState final localSessionMessage = tr( 'msg.userfront.login.verification.approved_local', ); - final linkLoginMessage = tr('msg.userfront.login.link.approved'); try { final res = await AuthProxyService.verifyLoginCode( sanitizedLoginId, @@ -872,7 +870,6 @@ class _LoginScreenState extends ConsumerState } Future _handlePasswordLogin() async { - print("[Auth] _handlePasswordLogin START"); final input = _passwordLoginIdController.text.trim(); final password = _passwordController.text.trim(); if (input.isEmpty || password.isEmpty) { @@ -889,29 +886,23 @@ class _LoginScreenState extends ConsumerState } try { - print("[Auth] Calling AuthProxyService.loginWithPassword..."); final res = await AuthProxyService.loginWithPassword( loginId, password, loginChallenge: _loginChallenge, ); - print("[Auth] loginWithPassword response: $res"); final jwt = res['sessionJwt'] ?? res['sessionToken'] ?? res['token']; final provider = res['provider'] as String?; final redirectTo = res['redirectTo'] as String?; if (jwt != null) { - print("[Auth] JWT found, calling _onLoginSuccess. RedirectTo: $redirectTo"); _onLoginSuccess(jwt, provider: provider, redirectTo: redirectTo); } else if (redirectTo != null && redirectTo.isNotEmpty) { - print("[Auth] Only redirectTo found. Redirecting..."); webWindow.redirectTo(redirectTo); } else { - print("[Auth] No JWT and no redirectTo found."); } } catch (e) { - print("[Auth] _handlePasswordLogin Error: $e"); if (e.toString().contains("User not registered")) { _showUnregisteredDialog(); } else { @@ -1134,56 +1125,44 @@ class _LoginScreenState extends ConsumerState } Future _onLoginSuccess(String token, {String? provider, String? redirectTo}) async { - print("[Auth] _onLoginSuccess ENTRY. RedirectTo: $redirectTo, Token len: ${token.length}"); try { if (!mounted) { - print("[Auth] _onLoginSuccess: Not mounted, returning."); return; } // [Priority 1] Immediate External Redirection if (redirectTo != null && redirectTo.isNotEmpty) { - print("[Auth] _onLoginSuccess: Has redirectTo. Saving token and redirecting..."); try { final providerName = provider ?? AuthTokenStore.getProvider(); - print("[Auth] _onLoginSuccess: Provider resolved: $providerName"); AuthTokenStore.setToken(token, provider: providerName); - print("[Auth] _onLoginSuccess: Token saved to store."); } catch (stErr) { - print("[Auth] _onLoginSuccess: FAILED to save token: $stErr"); + // ignore } - print("[Auth] Calling webWindow.redirectTo: $redirectTo"); webWindow.redirectTo(redirectTo); // Removed await as it's void return; } // [Priority 2] OIDC Challenge Handling if (_loginChallenge != null && _loginChallenge!.isNotEmpty) { - print("[Auth] _onLoginSuccess: Has loginChallenge. Attempting auto-accept..."); try { // Save token first, it's needed for acceptance final providerName = provider ?? AuthTokenStore.getProvider(); AuthTokenStore.setToken(token, provider: providerName); - print("[Auth] _onLoginSuccess: Token saved for auto-accept."); final res = await AuthProxyService.acceptOidcLogin( _loginChallenge!, token: token, ); final nextRedirectTo = res['redirectTo'] as String?; - print("[Auth] Auto-accept response: $res"); if (nextRedirectTo != null && nextRedirectTo.isNotEmpty) { - print("[Auth] OIDC login accepted. Redirecting to: $nextRedirectTo"); webWindow.redirectTo(nextRedirectTo); // Removed await return; } else { - print("[Auth] Auto-accept successful but no redirectTo provided."); } } catch (e) { - print("[Auth] Auto-accept failed: $e"); _showError( tr( 'msg.userfront.login.oidc_failed', @@ -1193,7 +1172,6 @@ class _LoginScreenState extends ConsumerState } } - print("[Auth] _onLoginSuccess: Standard Login Flow"); _logTokenDetails(token); final providerName = provider ?? AuthTokenStore.getProvider(); @@ -1205,7 +1183,7 @@ class _LoginScreenState extends ConsumerState try { await ref.read(profileProvider.notifier).loadProfile(); } catch (e) { - print("[Auth] Failed to pre-fetch profile: $e"); + // ignore } final uri = Uri.base; @@ -1215,21 +1193,17 @@ class _LoginScreenState extends ConsumerState redirectParam != null && redirectParam.isNotEmpty; if (WebAuthIntegration.isPopup() || hasRedirectParam) { - print( - "[Auth] External integration detected (popup or redirect). Notifying...", - ); WebAuthIntegration.sendLoginSuccess(token); AuthNotifier.instance.notify(); return; } - print("[Auth] Login success. Navigating to root."); AuthNotifier.instance.notify(); if (mounted) { context.go('/'); } } catch (globalErr) { - print("[Auth] CRITICAL ERROR in _onLoginSuccess: $globalErr"); + // ignore } } diff --git a/userfront/lib/features/auth/presentation/signup_screen.dart b/userfront/lib/features/auth/presentation/signup_screen.dart index 6844ef01..d9ecb9ba 100644 --- a/userfront/lib/features/auth/presentation/signup_screen.dart +++ b/userfront/lib/features/auth/presentation/signup_screen.dart @@ -1286,10 +1286,12 @@ class _SignupScreenState extends State { @override Widget build(BuildContext context) { bool canGoNext = false; - if (_currentStep == 1 && _termsAccepted && _privacyAccepted) + if (_currentStep == 1 && _termsAccepted && _privacyAccepted) { canGoNext = true; - if (_currentStep == 2 && _isEmailVerified && _isPhoneVerified) + } + if (_currentStep == 2 && _isEmailVerified && _isPhoneVerified) { canGoNext = true; + } if (_currentStep == 3) { final nameOk = _nameController.text.trim().isNotEmpty; if (_affiliationType == 'GENERAL') { diff --git a/userfront/lib/main.dart b/userfront/lib/main.dart index 677bfd76..071f318f 100644 --- a/userfront/lib/main.dart +++ b/userfront/lib/main.dart @@ -1,3 +1,4 @@ +// ignore_for_file: avoid_print import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -120,7 +121,6 @@ final _router = GoRouter( GoRoute( path: '', // Matches /:locale builder: (context, state) { - print("[Router] Building Dashboard (Root)"); return const DashboardScreen(); }, ), @@ -134,7 +134,6 @@ final _router = GoRouter( final loginChallenge = state.uri.queryParameters['login_challenge']; final redirectUrl = state.uri.queryParameters['redirect_uri'] ?? state.uri.queryParameters['redirect_url']; - print("[Router] Building /signin. Challenge: $loginChallenge"); return LoginScreen( key: state.pageKey, loginChallenge: loginChallenge, @@ -149,7 +148,6 @@ final _router = GoRouter( final loginChallenge = state.uri.queryParameters['login_challenge']; final redirectUrl = state.uri.queryParameters['redirect_uri'] ?? state.uri.queryParameters['redirect_url']; - print("[Router] Building /login (as signin). Challenge: $loginChallenge"); return LoginScreen( key: state.pageKey, loginChallenge: loginChallenge, @@ -162,12 +160,10 @@ final _router = GoRouter( builder: (BuildContext context, GoRouterState state) { final consentChallenge = state.uri.queryParameters['consent_challenge']; if (consentChallenge == null) { - print("[Router] WARNING: Consent screen without challenge."); return const Scaffold( body: Center(child: Text('Error: Consent challenge is missing.')), ); } - print("[Router] Building /consent. Challenge: $consentChallenge"); return ConsentScreen(consentChallenge: consentChallenge); }, ), @@ -200,7 +196,6 @@ final _router = GoRouter( GoRoute( path: 'l/:shortCode', builder: (context, state) { - final shortCode = state.pathParameters['shortCode']; return LoginScreen(key: state.pageKey); }, ), @@ -264,11 +259,8 @@ final _router = GoRouter( final requestedLocale = extractLocaleFromPath(uri); final preferredLocale = resolvePreferredLocaleCode(); - print("[Router] Redirect check for: $uri"); - if (requestedLocale == null) { final localizedPath = buildLocalizedPath(preferredLocale, uri); - print("[Router] Locale missing. Redirecting to: $localizedPath"); return localizedPath; } @@ -296,22 +288,12 @@ final _router = GoRouter( path.startsWith('/consent/') || uri.path.contains('/consent'); - print("[Router] Path: $path, IsLoggedIn: $isLoggedIn, IsPublic: $isPublicPath"); - if (isPublicPath) { return null; } if (!isLoggedIn) { - print("[Router] ACCESS DENIED. Redirecting to /signin"); - final locale = requestedLocale; - final newPath = '/$locale/signin'; - - // Preserve ALL query parameters - final finalRedirect = uri.replace(path: newPath); - String result = finalRedirect.path; - if (finalRedirect.hasQuery) result += '?${finalRedirect.query}'; - return result; + return buildSigninRedirectPath(requestedLocale, uri); } return null; diff --git a/userfront/test/helpers/web_storage_web.dart b/userfront/test/helpers/web_storage_web.dart index b9bbc1b8..bcb4be4c 100644 --- a/userfront/test/helpers/web_storage_web.dart +++ b/userfront/test/helpers/web_storage_web.dart @@ -1,36 +1,36 @@ // ignore_for_file: avoid_web_libraries_in_flutter -import 'dart:html' as html; +import 'package:web/web.dart' as web; class WebStorage { bool get isWeb => true; - String? get(String key) => html.window.localStorage[key]; + String? get(String key) => web.window.localStorage.getItem(key); void set(String key, String value) { - html.window.localStorage[key] = value; + web.window.localStorage.setItem(key, value); } - String? getSession(String key) => html.window.sessionStorage[key]; + String? getSession(String key) => web.window.sessionStorage.getItem(key); void setSession(String key, String value) { - html.window.sessionStorage[key] = value; + web.window.sessionStorage.setItem(key, value); } void removeSession(String key) { - html.window.sessionStorage.remove(key); + web.window.sessionStorage.removeItem(key); } void clearSession() { - html.window.sessionStorage.clear(); + web.window.sessionStorage.clear(); } void remove(String key) { - html.window.localStorage.remove(key); + web.window.localStorage.removeItem(key); } void clear() { - html.window.localStorage.clear(); + web.window.localStorage.clear(); } }