import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../../services/admin_service.dart'; import '../../services/subscription_service.dart'; import '../../models/subscription_model.dart'; import '../../widgets/dialog_actions.dart'; /// 관리자 대시보드 화면 class AdminDashboardScreen extends StatefulWidget { const AdminDashboardScreen({super.key}); @override State createState() => _AdminDashboardScreenState(); } class _AdminDashboardScreenState extends State { Map? _analyticsData; bool _isLoading = false; @override void initState() { super.initState(); _loadData(); } /// 데이터 로드 Future _loadData() async { setState(() { _isLoading = true; }); try { final adminService = Provider.of(context, listen: false); final analyticsData = await adminService.fetchClubAnalytics(); if (!mounted) return; setState(() { _analyticsData = analyticsData; }); } catch (e) { final messenger = ScaffoldMessenger.of(context); messenger.showSnackBar( SnackBar(content: Text('데이터 로드 중 오류가 발생했습니다: $e')), ); } finally { if (mounted) { setState(() { _isLoading = false; }); } } } @override Widget build(BuildContext context) { final adminService = Provider.of(context); final subscriptionService = Provider.of(context); return Scaffold( appBar: AppBar( title: const Text('관리자 대시보드'), actions: [ IconButton( icon: const Icon(Icons.refresh), onPressed: _loadData, ), ], ), body: _isLoading ? const Center(child: CircularProgressIndicator()) : RefreshIndicator( onRefresh: _loadData, child: SingleChildScrollView( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildPermissionsCard(adminService), const SizedBox(height: 16), _buildSubscriptionCard(subscriptionService), const SizedBox(height: 16), _buildAnalyticsCard(), const SizedBox(height: 16), _buildQuickActionsCard(context, adminService), ], ), ), ), ); } /// 권한 정보 카드 Widget _buildPermissionsCard(AdminService adminService) { return Card( elevation: 2, child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ const Icon(Icons.admin_panel_settings), const SizedBox(width: 8), Text( '관리자 권한', style: Theme.of(context).textTheme.titleLarge, ), ], ), const Divider(), const SizedBox(height: 8), _buildPermissionItem( '회원 관리', adminService.canManageMembers, Icons.people, ), _buildPermissionItem( '이벤트 관리', adminService.canManageEvents, Icons.event, ), _buildPermissionItem( '점수 관리', adminService.canManageScores, Icons.score, ), _buildPermissionItem( '설정 관리', adminService.canManageSettings, Icons.settings, ), _buildPermissionItem( '구독 관리', adminService.canManageSubscription, Icons.subscriptions, ), _buildPermissionItem( '역할 관리', adminService.canManageRoles, Icons.admin_panel_settings, ), _buildPermissionItem( '재무 정보 조회', adminService.canViewFinancials, Icons.attach_money, ), _buildPermissionItem( '데이터 내보내기', adminService.canExportData, Icons.file_download, ), ], ), ), ); } /// 권한 항목 위젯 Widget _buildPermissionItem(String title, bool hasPermission, IconData icon) { return Padding( padding: const EdgeInsets.symmetric(vertical: 4.0), child: Row( children: [ Icon( icon, size: 18, color: hasPermission ? Colors.green : Colors.grey, ), const SizedBox(width: 8), Text(title), const Spacer(), Icon( hasPermission ? Icons.check_circle : Icons.cancel, color: hasPermission ? Colors.green : Colors.red, size: 18, ), ], ), ); } /// 구독 정보 카드 Widget _buildSubscriptionCard(SubscriptionService subscriptionService) { final subscription = subscriptionService.currentSubscription; return Card( elevation: 2, child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ const Icon(Icons.subscriptions), const SizedBox(width: 8), Text( '구독 정보', style: Theme.of(context).textTheme.titleLarge, ), ], ), const Divider(), const SizedBox(height: 8), if (subscription != null) ...[ _buildInfoRow('플랜', subscription.planName), _buildInfoRow('상태', _getStatusText(subscription.status)), _buildInfoRow('시작일', _formatDate(subscription.startDate)), _buildInfoRow('만료일', _formatDate(subscription.endDate)), _buildInfoRow('자동 갱신', subscription.autoRenew ? '활성화' : '비활성화'), _buildInfoRow('남은 일수', '${subscription.daysLeft}일'), ] else const Text('활성화된 구독이 없습니다.'), const SizedBox(height: 16), ElevatedButton( onPressed: () { Navigator.of(context).pushNamed('/subscription/manage'); }, child: const Text('구독 관리'), ), ], ), ), ); } /// 분석 데이터 카드 Widget _buildAnalyticsCard() { return Card( elevation: 2, child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ const Icon(Icons.analytics), const SizedBox(width: 8), Text( '클럽 통계', style: Theme.of(context).textTheme.titleLarge, ), ], ), const Divider(), const SizedBox(height: 8), if (_analyticsData != null) ...[ _buildInfoRow('총 회원 수', '${_analyticsData!['totalMembers'] ?? 0}명'), _buildInfoRow('활성 회원 수', '${_analyticsData!['activeMembers'] ?? 0}명'), _buildInfoRow('이번 달 신규 회원', '${_analyticsData!['newMembersThisMonth'] ?? 0}명'), _buildInfoRow('총 이벤트 수', '${_analyticsData!['totalEvents'] ?? 0}개'), _buildInfoRow('이번 달 이벤트', '${_analyticsData!['eventsThisMonth'] ?? 0}개'), _buildInfoRow('총 게임 수', '${_analyticsData!['totalGames'] ?? 0}게임'), _buildInfoRow('평균 점수', '${_analyticsData!['averageScore'] ?? 0}점'), ] else const Text('통계 데이터를 불러올 수 없습니다.'), ], ), ), ); } /// 빠른 작업 카드 Widget _buildQuickActionsCard(BuildContext context, AdminService adminService) { return Card( elevation: 2, child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ const Icon(Icons.flash_on), const SizedBox(width: 8), Text( '빠른 작업', style: Theme.of(context).textTheme.titleLarge, ), ], ), const Divider(), const SizedBox(height: 8), Wrap( spacing: 8.0, runSpacing: 8.0, children: [ if (adminService.canManageMembers) _buildActionButton( context, '회원 관리', Icons.people, () => Navigator.of(context).pushNamed('/admin/members'), ), if (adminService.canManageEvents) _buildActionButton( context, '이벤트 관리', Icons.event, () => Navigator.of(context).pushNamed('/admin/events'), ), if (adminService.canManageSettings) _buildActionButton( context, '클럽 설정', Icons.settings, () => Navigator.of(context).pushNamed('/admin/settings'), ), if (adminService.canManageRoles) _buildActionButton( context, '역할 관리', Icons.admin_panel_settings, () => Navigator.of(context).pushNamed('/admin/roles'), ), if (adminService.canExportData) _buildActionButton( context, '데이터 내보내기', Icons.file_download, () => _showExportDialog(context), ), ], ), ], ), ), ); } /// 작업 버튼 위젯 Widget _buildActionButton( BuildContext context, String label, IconData icon, VoidCallback onPressed, ) { return ElevatedButton.icon( onPressed: onPressed, icon: Icon(icon, size: 18), label: Text(label), style: ElevatedButton.styleFrom( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), ), ); } /// 데이터 내보내기 다이얼로그 void _showExportDialog(BuildContext context) { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('데이터 내보내기'), content: Column( mainAxisSize: MainAxisSize.min, children: [ ListTile( leading: const Icon(Icons.people), title: const Text('회원 데이터'), onTap: () => _exportData(context, 'members'), ), ListTile( leading: const Icon(Icons.event), title: const Text('이벤트 데이터'), onTap: () => _exportData(context, 'events'), ), ListTile( leading: const Icon(Icons.score), title: const Text('점수 데이터'), onTap: () => _exportData(context, 'scores'), ), ListTile( leading: const Icon(Icons.analytics), title: const Text('통계 데이터'), onTap: () => _exportData(context, 'analytics'), ), ], ), actions: DialogActions.confirm( onCancel: () => Navigator.of(context).pop(), onConfirm: () => Navigator.of(context).pop(), confirmText: '닫기', ), ), ); } /// 데이터 내보내기 처리 Future _exportData(BuildContext context, String dataType) async { final navigator = Navigator.of(context); final messenger = ScaffoldMessenger.of(context); navigator.pop(); // 다이얼로그 닫기 setState(() { _isLoading = true; }); try { final adminService = Provider.of(context, listen: false); final downloadUrl = await adminService.exportClubData(dataType); if (downloadUrl != null) { messenger.showSnackBar( SnackBar(content: Text('데이터 내보내기 성공: $downloadUrl')), ); } else { messenger.showSnackBar( const SnackBar(content: Text('데이터 내보내기에 실패했습니다.')), ); } } catch (e) { messenger.showSnackBar( SnackBar(content: Text('데이터 내보내기 중 오류가 발생했습니다: $e')), ); } finally { if (mounted) { setState(() { _isLoading = false; }); } } } /// 정보 행 위젯 Widget _buildInfoRow(String label, String value) { return Padding( padding: const EdgeInsets.symmetric(vertical: 4.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( '$label:', style: const TextStyle(fontWeight: FontWeight.bold), ), Text(value), ], ), ); } /// 날짜 포맷팅 String _formatDate(DateTime date) { return '${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}'; } /// 구독 상태 텍스트 String _getStatusText(SubscriptionStatus status) { switch (status) { case SubscriptionStatus.active: return '활성화'; case SubscriptionStatus.canceled: return '취소됨'; case SubscriptionStatus.expired: return '만료됨'; case SubscriptionStatus.pending: return '대기 중'; case SubscriptionStatus.failed: return '실패'; } } }