import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:intl/intl.dart'; import 'package:superport/screens/common/theme_shadcn.dart'; import 'package:superport/screens/common/components/shadcn_components.dart'; import 'package:superport/screens/overview/controllers/overview_controller.dart'; import 'package:superport/services/mock_data_service.dart'; /// shadcn/ui 스타일로 재설계된 대시보드 화면 class OverviewScreenRedesign extends StatefulWidget { const OverviewScreenRedesign({Key? key}) : super(key: key); @override State createState() => _OverviewScreenRedesignState(); } class _OverviewScreenRedesignState extends State { late final OverviewController _controller; @override void initState() { super.initState(); _controller = OverviewController(); _loadData(); } Future _loadData() async { await _controller.loadDashboardData(); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return ChangeNotifierProvider.value( value: _controller, child: Consumer( builder: (context, controller, child) { if (controller.isLoading) { return _buildLoadingState(); } if (controller.error != null) { return _buildErrorState(controller.error!); } return Container( color: ShadcnTheme.background, child: SingleChildScrollView( padding: const EdgeInsets.all(24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 환영 섹션 ShadcnCard( padding: const EdgeInsets.all(32), child: Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('안녕하세요, 관리자님! 👋', style: ShadcnTheme.headingH3), const SizedBox(height: 8), Text( '오늘의 포트 운영 현황을 확인해보세요.', style: ShadcnTheme.bodyMuted, ), const SizedBox(height: 16), Row( children: [ ShadcnBadge( text: '실시간 모니터링', variant: ShadcnBadgeVariant.success, ), const SizedBox(width: 8), ShadcnBadge( text: '업데이트됨', variant: ShadcnBadgeVariant.outline, ), ], ), ], ), ), ], ), ), const SizedBox(height: 32), // 통계 카드 그리드 (반응형) LayoutBuilder( builder: (context, constraints) { final crossAxisCount = constraints.maxWidth > 1200 ? 4 : constraints.maxWidth > 800 ? 2 : 1; return GridView.count( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), crossAxisCount: crossAxisCount, crossAxisSpacing: 16, mainAxisSpacing: 16, childAspectRatio: 1.5, children: [ _buildStatCard( '총 회사 수', '${_controller.totalCompanies}', Icons.business, ShadcnTheme.gradient1, ), _buildStatCard( '총 사용자 수', '${_controller.totalUsers}', Icons.people, ShadcnTheme.gradient2, ), _buildStatCard( '입고 장비', '${_controller.overviewStats?.availableEquipment ?? 0}', Icons.inventory, ShadcnTheme.success, ), _buildStatCard( '출고 장비', '${_controller.overviewStats?.inUseEquipment ?? 0}', Icons.local_shipping, ShadcnTheme.warning, ), ], ); }, ), const SizedBox(height: 32), // 하단 콘텐츠 LayoutBuilder( builder: (context, constraints) { if (constraints.maxWidth > 1000) { // 큰 화면: 가로로 배치 return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded(flex: 2, child: _buildLeftColumn()), const SizedBox(width: 24), Expanded(flex: 1, child: _buildRightColumn()), ], ); } else { // 작은 화면: 세로로 배치 return Column( children: [ _buildLeftColumn(), const SizedBox(height: 24), _buildRightColumn(), ], ); } }, ), ], ), ), ); }, ), ); } Widget _buildLoadingState() { return Container( color: ShadcnTheme.background, child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ CircularProgressIndicator(color: ShadcnTheme.primary), const SizedBox(height: ShadcnTheme.spacing4), Text('대시보드를 불러오는 중...', style: ShadcnTheme.bodyMuted), ], ), ), ); } Widget _buildErrorState(String error) { return Container( color: ShadcnTheme.background, child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.error_outline, size: 48, color: ShadcnTheme.error, ), const SizedBox(height: ShadcnTheme.spacing4), Text('오류가 발생했습니다', style: ShadcnTheme.headingH4), const SizedBox(height: ShadcnTheme.spacing2), Text(error, style: ShadcnTheme.bodyMuted), const SizedBox(height: ShadcnTheme.spacing4), ShadcnButton( text: '다시 시도', onPressed: _loadData, variant: ShadcnButtonVariant.primary, ), ], ), ), ); } Widget _buildLeftColumn() { return Column( children: [ // 차트 카드 ShadcnCard( padding: const EdgeInsets.all(24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('월별 활동 현황', style: ShadcnTheme.headingH4), Text('최근 6개월 데이터', style: ShadcnTheme.bodyMuted), ], ), ShadcnButton( text: '상세보기', onPressed: () {}, variant: ShadcnButtonVariant.ghost, size: ShadcnButtonSize.small, ), ], ), const SizedBox(height: 24), Container( height: 200, decoration: BoxDecoration( color: ShadcnTheme.muted, borderRadius: BorderRadius.circular(8), ), child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.analytics, size: 48, color: ShadcnTheme.mutedForeground, ), const SizedBox(height: 12), Text('차트 영역', style: ShadcnTheme.bodyMuted), Text( 'fl_chart 라이브러리로 구현 예정', style: ShadcnTheme.bodySmall, ), ], ), ), ), ], ), ), const SizedBox(height: 24), // 최근 활동 ShadcnCard( padding: const EdgeInsets.all(24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('최근 활동', style: ShadcnTheme.headingH4), ShadcnButton( text: '전체보기', onPressed: () {}, variant: ShadcnButtonVariant.ghost, size: ShadcnButtonSize.small, ), ], ), const SizedBox(height: 16), Consumer( builder: (context, controller, child) { final activities = controller.recentActivities ?? []; if (activities.isEmpty) { return Padding( padding: const EdgeInsets.symmetric(vertical: 20), child: Center( child: Text( '최근 활동이 없습니다', style: ShadcnTheme.bodyMuted, ), ), ); } return Column( children: activities.take(5).map((activity) => _buildActivityItem(activity), ).toList(), ); }, ), ], ), ), ], ); } Widget _buildRightColumn() { return Column( children: [ // 빠른 작업 ShadcnCard( padding: const EdgeInsets.all(24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('빠른 작업', style: ShadcnTheme.headingH4), const SizedBox(height: 16), _buildQuickActionButton(Icons.add_box, '장비 입고', '새 장비 등록'), const SizedBox(height: 12), _buildQuickActionButton( Icons.local_shipping, '장비 출고', '장비 대여 처리', ), const SizedBox(height: 12), _buildQuickActionButton( Icons.business_center, '회사 등록', '새 회사 추가', ), ], ), ), const SizedBox(height: 24), // 시스템 상태 ShadcnCard( padding: const EdgeInsets.all(24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('시스템 상태', style: ShadcnTheme.headingH4), const SizedBox(height: 16), _buildStatusItem('서버 상태', '정상'), _buildStatusItem('데이터베이스', '정상'), _buildStatusItem('네트워크', '정상'), _buildStatusItem('백업', '완료'), ], ), ), ], ); } Widget _buildStatCard( String title, String value, IconData icon, Color color, ) { return ShadcnCard( padding: const EdgeInsets.all(24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: color.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(6), ), child: Icon(icon, color: color, size: 20), ), Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: ShadcnTheme.success.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(12), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( Icons.trending_up, size: 12, color: ShadcnTheme.success, ), const SizedBox(width: 4), Text( '+2.3%', style: ShadcnTheme.labelSmall.copyWith( color: ShadcnTheme.success, ), ), ], ), ), ], ), const SizedBox(height: 16), Text(value, style: ShadcnTheme.headingH2), const SizedBox(height: 4), Text(title, style: ShadcnTheme.bodyMedium), Text('등록된 항목', style: ShadcnTheme.bodySmall), ], ), ); } Widget _buildActivityItem(dynamic activity) { // 아이콘 매핑 IconData getActivityIcon(String type) { switch (type) { case 'equipment_in': return Icons.inventory; case 'equipment_out': return Icons.local_shipping; case 'company': return Icons.business; case 'user': return Icons.person_add; default: return Icons.settings; } } // 색상 매핑 Color getActivityColor(String type) { switch (type) { case 'equipment_in': return ShadcnTheme.success; case 'equipment_out': return ShadcnTheme.warning; case 'company': return ShadcnTheme.info; case 'user': return ShadcnTheme.primary; default: return ShadcnTheme.mutedForeground; } } final color = getActivityColor(activity.activityType); final dateFormat = DateFormat('MM/dd HH:mm'); return Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: Row( children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: color.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(6), ), child: Icon( getActivityIcon(activity.activityType), color: color, size: 16, ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( activity.entityName, style: ShadcnTheme.bodyMedium, ), Text( activity.description, style: ShadcnTheme.bodySmall, ), ], ), ), Text( dateFormat.format(activity.timestamp), style: ShadcnTheme.bodySmall, ), ], ), ); } Widget _buildQuickActionButton(IconData icon, String title, String subtitle) { return GestureDetector( onTap: () { // 실제 기능 구현 ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('$title 기능은 개발 중입니다.'), backgroundColor: ShadcnTheme.info, ), ); }, child: Container( width: double.infinity, padding: const EdgeInsets.all(16), decoration: BoxDecoration( border: Border.all(color: ShadcnTheme.border), borderRadius: BorderRadius.circular(6), ), child: Row( children: [ Icon(icon, color: ShadcnTheme.primary), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(title, style: ShadcnTheme.bodyMedium), Text(subtitle, style: ShadcnTheme.bodySmall), ], ), ), Icon( Icons.arrow_forward_ios, size: 16, color: ShadcnTheme.mutedForeground, ), ], ), ), ); } Widget _buildStatusItem(String label, String status) { return Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(label, style: ShadcnTheme.bodyMedium), ShadcnBadge( text: status, variant: ShadcnBadgeVariant.success, size: ShadcnBadgeSize.small, ), ], ), ); } }