From 69b1257ad7d1c2bff9c8b5c202085a73f1e85834 Mon Sep 17 00:00:00 2001 From: kyy Date: Tue, 3 Feb 2026 15:04:14 +0900 Subject: [PATCH] =?UTF-8?q?=EB=8F=99=EC=9D=98=20=ED=99=94=EB=A9=B4=20'?= =?UTF-8?q?=EC=B7=A8=EC=86=8C'=20=EA=B8=B0=EB=8A=A5=20=EB=B0=8F=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=20=EB=8B=A4=EC=9D=B4=EC=96=BC=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/presentation/consent_screen.dart | 73 +++++++++++++++---- 1 file changed, 58 insertions(+), 15 deletions(-) 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(