diff --git a/userfront/lib/features/auth/presentation/consent_screen.dart b/userfront/lib/features/auth/presentation/consent_screen.dart index 33e8d1a2..93c7a761 100644 --- a/userfront/lib/features/auth/presentation/consent_screen.dart +++ b/userfront/lib/features/auth/presentation/consent_screen.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; import 'package:userfront/core/services/auth_proxy_service.dart'; import 'package:userfront/core/services/web_window.dart'; @@ -103,27 +104,60 @@ class _ConsentScreenState extends State { ); if (result['redirectTo'] != null) { - html.window.location.href = result['redirectTo']; + webWindow.redirectTo(result['redirectTo']); } else { setState(() { _error = '동의가 처리되었으나, 리다이렉트 URL을 받지 못했습니다.'; - _isLoading = false; + _isSubmitting = false; }); } } catch (e) { setState(() { _error = '동의 처리에 실패했습니다: $e'; - _isLoading = false; + _isSubmitting = false; }); } } - void _onCancel() { - // 취소 시 동작 (창 닫기 시도 또는 알림) - // 실제 프로덕션에서는 Hydra reject API를 호출하고 리다이렉트 하는 것이 좋습니다. - // 현재는 요구사항에 따라 간단히 처리합니다. - html.window.alert('동의를 취소했습니다. 창을 닫아주세요.'); - // html.window.close(); // 브라우저 정책상 스크립트로 연 창이 아니면 닫히지 않을 수 있음 + Future _onCancel() async { + final confirmed = await showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('동의 취소'), + content: const Text('권한 동의를 취소하면 해당 서비스를 이용할 수 없습니다. 취소하시겠습니까?'), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context, false), + child: const Text('아니오'), + ), + TextButton( + onPressed: () => Navigator.pop(context, true), + style: TextButton.styleFrom(foregroundColor: Colors.red), + child: const Text('예, 취소합니다'), + ), + ], + ), + ); + + if (confirmed == true) { + setState(() => _isSubmitting = true); + try { + final resp = await AuthProxyService.rejectConsent(widget.consentChallenge); + final redirectTo = resp['redirectTo']; + if (redirectTo != null) { + webWindow.redirectTo(redirectTo); + } else { + if (mounted) context.go('/'); + } + } catch (e) { + setState(() => _isSubmitting = false); + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('취소 처리 중 오류가 발생했습니다: $e')), + ); + } + } + } } @override @@ -299,7 +333,7 @@ class _ConsentScreenState extends State { // 4. 버튼 영역 ElevatedButton( - onPressed: _acceptConsent, + onPressed: _isSubmitting ? null : _acceptConsent, style: ElevatedButton.styleFrom( padding: const EdgeInsets.symmetric(vertical: 16), backgroundColor: const Color(0xFF1A1F2C), // 브랜드 컬러 @@ -309,14 +343,23 @@ class _ConsentScreenState extends State { ), elevation: 0, ), - child: const Text( - '동의하고 계속하기', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), + child: _isSubmitting + ? const SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + color: Colors.white, + ), + ) + : const Text( + '동의하고 계속하기', + style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + ), ), const SizedBox(height: 12), OutlinedButton( - onPressed: _onCancel, + onPressed: _isSubmitting ? null : _onCancel, style: OutlinedButton.styleFrom( padding: const EdgeInsets.symmetric(vertical: 16), shape: RoundedRectangleBorder(