1
0
forked from baron/baron-sso

RP 활성화/비활성화 UX 개선

This commit is contained in:
2026-02-04 10:38:41 +09:00
parent 1f1e7b6ce7
commit 1a02c15e78

View File

@@ -164,6 +164,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
Future<List<LinkedRp>>? _linkedRpsFuture;
bool _showAllActivities = false;
final Set<String> _revokedClientIds = {};
@override
void initState() {
@@ -213,7 +214,9 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('$appName 연동이 해지되었습니다.')),
);
_refreshAll();
setState(() {
_revokedClientIds.add(clientId);
});
}
} catch (e) {
if (mounted) {
@@ -297,6 +300,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
await ref.read(profileProvider.notifier).loadProfile();
await _loadAuditLogs(reset: true);
setState(() {
_revokedClientIds.clear();
_linkedRpsFuture = _fetchLinkedRps();
});
if (_linkedRpsFuture != null) {
@@ -866,11 +870,13 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
List<_ActivityItem> _buildActivityItems(List<LinkedRp> linkedRps) {
final items = <_ActivityItem>[];
for (final rp in linkedRps) {
final isRevoked = _revokedClientIds.contains(rp.id);
final lastAuthLabel = rp.lastAuthenticatedAt != null
? _formatDateTime(rp.lastAuthenticatedAt!)
: '연동됨';
final normalizedStatus = rp.status.toLowerCase();
final statusLabel = normalizedStatus.isEmpty || normalizedStatus == 'active' ? '활성' : '비활성';
final statusLabel = isRevoked ? '비활성' : (normalizedStatus.isEmpty || normalizedStatus == 'active' ? '활성' : '비활성');
final name = rp.name.isNotEmpty ? rp.name : rp.id;
items.add(
_ActivityItem(
@@ -879,7 +885,8 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
lastAuthAt: lastAuthLabel,
status: statusLabel,
canLogout: false,
onRevoke: () => _onRevokeLink(rp.id, name),
isRevoked: isRevoked,
onRevoke: isRevoked ? null : () => _onRevokeLink(rp.id, name),
),
);
}
@@ -933,85 +940,99 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
}
Widget _buildActivityCard(_ActivityItem item) {
final statusColor = item.status == '활성' ? Colors.green : Colors.grey;
return Container(
width: 260,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: _surface,
borderRadius: BorderRadius.circular(14),
border: Border.all(color: _border),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
item.appName,
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: _ink),
final isActive = item.status == '활성';
final statusColor = isActive ? Colors.green : Colors.grey;
final borderColor = isActive ? Colors.green.withOpacity(0.5) : _border;
final borderWidth = isActive ? 1.5 : 1.0;
return Opacity(
opacity: item.isRevoked ? 0.6 : 1.0,
child: Container(
width: 260,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: _surface,
borderRadius: BorderRadius.circular(14),
border: Border.all(color: borderColor, width: borderWidth),
boxShadow: isActive ? [
BoxShadow(
color: Colors.green.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 4),
)
] : null,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
item.appName,
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: _ink),
),
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: statusColor.withOpacity(0.12),
borderRadius: BorderRadius.circular(999),
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: statusColor.withOpacity(0.12),
borderRadius: BorderRadius.circular(999),
),
child: Text(
item.status,
style: TextStyle(fontSize: 11, color: statusColor, fontWeight: FontWeight.w600),
),
),
child: Text(
item.status,
style: TextStyle(fontSize: 11, color: statusColor, fontWeight: FontWeight.w600),
),
),
],
),
const SizedBox(height: 12),
Text(
'최근 인증',
style: TextStyle(fontSize: 12, color: Colors.grey[600]),
),
const SizedBox(height: 4),
Text(
item.lastAuthAt,
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w600, color: _ink),
),
const SizedBox(height: 16),
Row(
children: [
if (item.canLogout)
],
),
const SizedBox(height: 12),
Text(
'최근 인증',
style: TextStyle(fontSize: 12, color: Colors.grey[600]),
),
const SizedBox(height: 4),
Text(
item.lastAuthAt,
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w600, color: _ink),
),
const SizedBox(height: 16),
Row(
children: [
if (item.canLogout)
Expanded(
child: OutlinedButton(
onPressed: item.onLogout,
style: OutlinedButton.styleFrom(
foregroundColor: _ink,
side: const BorderSide(color: _border),
padding: const EdgeInsets.symmetric(vertical: 8),
),
child: const Text('로그아웃', style: TextStyle(fontSize: 13)),
),
),
if (item.canLogout) const SizedBox(width: 8),
Expanded(
child: OutlinedButton(
onPressed: item.onLogout,
onPressed: (_isRevoking || item.isRevoked) ? null : item.onRevoke,
style: OutlinedButton.styleFrom(
foregroundColor: _ink,
side: const BorderSide(color: _border),
foregroundColor: item.isRevoked ? Colors.grey : Colors.redAccent,
side: BorderSide(color: item.isRevoked ? Colors.grey : Colors.redAccent, width: 0.5),
padding: const EdgeInsets.symmetric(vertical: 8),
),
child: const Text('로그아웃', style: TextStyle(fontSize: 13)),
child: _isRevoking && !item.isRevoked
? const SizedBox(
width: 14,
height: 14,
child: CircularProgressIndicator(strokeWidth: 2, color: Colors.redAccent),
)
: Text(item.isRevoked ? '해지됨' : '연동 해지', style: const TextStyle(fontSize: 13)),
),
),
if (item.canLogout) const SizedBox(width: 8),
Expanded(
child: OutlinedButton(
onPressed: _isRevoking ? null : item.onRevoke,
style: OutlinedButton.styleFrom(
foregroundColor: Colors.redAccent,
side: const BorderSide(color: Colors.redAccent, width: 0.5),
padding: const EdgeInsets.symmetric(vertical: 8),
),
child: _isRevoking
? const SizedBox(
width: 14,
height: 14,
child: CircularProgressIndicator(strokeWidth: 2, color: Colors.redAccent),
)
: const Text('연동 해지', style: TextStyle(fontSize: 13)),
),
),
],
),
],
],
),
],
),
),
);
}
@@ -1212,6 +1233,7 @@ class _ActivityItem {
final String lastAuthAt;
final String status;
final bool canLogout;
final bool isRevoked;
final VoidCallback? onLogout;
final VoidCallback? onRevoke;
@@ -1221,7 +1243,8 @@ class _ActivityItem {
required this.lastAuthAt,
required this.status,
required this.canLogout,
this.isRevoked = false,
this.onLogout,
this.onRevoke,
});
}
}