import 'package:flutter/material.dart'; import 'package:superport/models/user_model.dart'; import 'package:superport/screens/common/theme_shadcn.dart'; import 'package:superport/screens/common/components/shadcn_components.dart'; import 'package:superport/screens/user/controllers/user_list_controller.dart'; import 'package:superport/utils/constants.dart'; import 'package:superport/services/mock_data_service.dart'; /// shadcn/ui 스타일로 재설계된 사용자 관리 화면 class UserListRedesign extends StatefulWidget { const UserListRedesign({super.key}); @override State createState() => _UserListRedesignState(); } class _UserListRedesignState extends State { late final UserListController _controller; final MockDataService _dataService = MockDataService(); int _currentPage = 1; final int _pageSize = 10; @override void initState() { super.initState(); _controller = UserListController(dataService: _dataService); _controller.loadUsers(); _controller.addListener(_refresh); } @override void dispose() { _controller.removeListener(_refresh); super.dispose(); } /// 상태 갱신용 setState 래퍼 void _refresh() { setState(() {}); } /// 회사명 반환 함수 String _getCompanyName(int companyId) { final company = _dataService.getCompanyById(companyId); return company?.name ?? '-'; } /// 사용자 권한 표시 배지 Widget _buildUserRoleBadge(String role) { switch (role) { case 'S': return ShadcnBadge( text: '관리자', variant: ShadcnBadgeVariant.destructive, size: ShadcnBadgeSize.small, ); case 'M': return ShadcnBadge( text: '멤버', variant: ShadcnBadgeVariant.primary, size: ShadcnBadgeSize.small, ); default: return ShadcnBadge( text: '사용자', variant: ShadcnBadgeVariant.outline, size: ShadcnBadgeSize.small, ); } } /// 사용자 추가 폼으로 이동 void _navigateToAdd() async { final result = await Navigator.pushNamed(context, Routes.userAdd); if (result == true) { _controller.loadUsers(); } } /// 사용자 수정 폼으로 이동 void _navigateToEdit(int userId) async { final result = await Navigator.pushNamed( context, Routes.userEdit, arguments: userId, ); if (result == true) { _controller.loadUsers(); } } /// 사용자 삭제 다이얼로그 void _showDeleteDialog(int userId) { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('사용자 삭제'), content: const Text('정말로 삭제하시겠습니까?'), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('취소'), ), TextButton( onPressed: () { _controller.deleteUser(userId, () { setState(() {}); }); Navigator.of(context).pop(); }, child: const Text('삭제'), ), ], ), ); } @override Widget build(BuildContext context) { final int totalCount = _controller.users.length; final int startIndex = (_currentPage - 1) * _pageSize; final int endIndex = (startIndex + _pageSize) > totalCount ? totalCount : (startIndex + _pageSize); final List pagedUsers = _controller.users.sublist( startIndex, endIndex, ); return SingleChildScrollView( padding: const EdgeInsets.all(ShadcnTheme.spacing6), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 헤더 액션 바 Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('총 $totalCount명 사용자', style: ShadcnTheme.bodyMuted), Row( children: [ ShadcnButton( text: '새로고침', onPressed: _controller.loadUsers, variant: ShadcnButtonVariant.secondary, icon: Icon(Icons.refresh), ), const SizedBox(width: ShadcnTheme.spacing2), ShadcnButton( text: '사용자 추가', onPressed: _navigateToAdd, variant: ShadcnButtonVariant.primary, textColor: Colors.white, icon: Icon(Icons.add), ), ], ), ], ), const SizedBox(height: ShadcnTheme.spacing4), // 테이블 컨테이너 Expanded( child: Container( width: double.infinity, decoration: BoxDecoration( border: Border.all(color: ShadcnTheme.border), borderRadius: BorderRadius.circular(ShadcnTheme.radiusMd), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 테이블 헤더 Container( padding: const EdgeInsets.symmetric( horizontal: ShadcnTheme.spacing4, vertical: ShadcnTheme.spacing3, ), decoration: BoxDecoration( color: ShadcnTheme.muted.withValues(alpha: 0.3), border: Border( bottom: BorderSide(color: ShadcnTheme.border), ), ), child: Row( children: [ Expanded( flex: 1, child: Text('번호', style: ShadcnTheme.bodyMedium), ), Expanded( flex: 2, child: Text('사용자명', style: ShadcnTheme.bodyMedium), ), Expanded( flex: 2, child: Text('이메일', style: ShadcnTheme.bodyMedium), ), Expanded( flex: 2, child: Text('회사명', style: ShadcnTheme.bodyMedium), ), Expanded( flex: 2, child: Text('지점명', style: ShadcnTheme.bodyMedium), ), Expanded( flex: 1, child: Text('권한', style: ShadcnTheme.bodyMedium), ), Expanded( flex: 1, child: Text('관리', style: ShadcnTheme.bodyMedium), ), ], ), ), // 테이블 데이터 if (pagedUsers.isEmpty) Container( padding: const EdgeInsets.all(ShadcnTheme.spacing8), child: Center( child: Text( '등록된 사용자가 없습니다.', style: ShadcnTheme.bodyMuted, ), ), ) else ...pagedUsers.asMap().entries.map((entry) { final int index = entry.key; final User user = entry.value; return Container( padding: const EdgeInsets.all(ShadcnTheme.spacing4), decoration: BoxDecoration( border: Border( bottom: BorderSide(color: ShadcnTheme.border), ), ), child: Row( children: [ // 번호 Expanded( flex: 1, child: Text( '${startIndex + index + 1}', style: ShadcnTheme.bodySmall, ), ), // 사용자명 Expanded( flex: 2, child: Text( user.name, style: ShadcnTheme.bodyMedium, ), ), // 이메일 Expanded( flex: 2, child: Text( user.email ?? '미등록', style: ShadcnTheme.bodySmall, ), ), // 회사명 Expanded( flex: 2, child: Text( _getCompanyName(user.companyId), style: ShadcnTheme.bodySmall, ), ), // 지점명 Expanded( flex: 2, child: Text( _controller.getBranchName( user.companyId, user.branchId, ), style: ShadcnTheme.bodySmall, ), ), // 권한 Expanded( flex: 1, child: _buildUserRoleBadge(user.role), ), // 관리 Expanded( flex: 1, child: Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( icon: Icon( Icons.edit, size: 16, color: ShadcnTheme.primary, ), onPressed: user.id != null ? () => _navigateToEdit(user.id!) : null, tooltip: '수정', ), IconButton( icon: Icon( Icons.delete, size: 16, color: ShadcnTheme.destructive, ), onPressed: user.id != null ? () => _showDeleteDialog(user.id!) : null, tooltip: '삭제', ), ], ), ), ], ), ); }), ], ), ), ), // 페이지네이션 if (totalCount > _pageSize) ...[ const SizedBox(height: ShadcnTheme.spacing6), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ ShadcnButton( text: '이전', onPressed: _currentPage > 1 ? () { setState(() { _currentPage--; }); } : null, variant: ShadcnButtonVariant.secondary, size: ShadcnButtonSize.small, ), const SizedBox(width: ShadcnTheme.spacing2), Text( '$_currentPage / ${(totalCount / _pageSize).ceil()}', style: ShadcnTheme.bodyMuted, ), const SizedBox(width: ShadcnTheme.spacing2), ShadcnButton( text: '다음', onPressed: _currentPage < (totalCount / _pageSize).ceil() ? () { setState(() { _currentPage++; }); } : null, variant: ShadcnButtonVariant.secondary, size: ShadcnButtonSize.small, ), ], ), ], ], ), ); } }