import 'package:flutter/material.dart' hide DataColumn; // Flutter DataColumn 숨기기 import 'package:provider/provider.dart'; // import '../../core/theme/app_theme.dart'; // 존재하지 않는 파일 - 주석 처리 import '../../data/models/rent_dto.dart'; import '../../injection_container.dart'; import '../common/widgets/standard_data_table.dart'; // StandardDataTable의 DataColumn 사용 import '../common/widgets/standard_action_bar.dart'; import '../common/widgets/standard_states.dart'; import '../common/widgets/pagination.dart'; import 'controllers/rent_controller.dart'; import 'rent_form_dialog.dart'; class RentListScreen extends StatefulWidget { const RentListScreen({super.key}); @override State createState() => _RentListScreenState(); } class _RentListScreenState extends State { late final RentController _controller; final _searchController = TextEditingController(); @override void initState() { super.initState(); _controller = getIt(); _loadData(); } @override void dispose() { _searchController.dispose(); super.dispose(); } Future _loadData() async { await _controller.loadRents(); } Future _refresh() async { await _controller.loadRents(refresh: true); } void _showCreateDialog() { showDialog( context: context, builder: (context) => RentFormDialog( onSubmit: (request) async { final success = await _controller.createRent( equipmentHistoryId: request.equipmentHistoryId, startedAt: request.startedAt, endedAt: request.endedAt, ); if (success && mounted) { Navigator.of(context).pop(); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('임대 계약이 생성되었습니다')), ); } return success; }, ), ); } void _showEditDialog(RentDto rent) { showDialog( context: context, builder: (context) => RentFormDialog( rent: rent, onSubmit: (request) async { final success = await _controller.updateRent( id: rent.id!, startedAt: request.startedAt, endedAt: request.endedAt, ); if (success && mounted) { Navigator.of(context).pop(); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('임대 계약이 수정되었습니다')), ); } return success; }, ), ); } Future _deleteRent(RentDto rent) async { final confirmed = await showDialog( context: context, builder: (context) => AlertDialog( title: const Text('임대 계약 삭제'), content: Text('ID ${rent.id}번 임대 계약을 삭제하시겠습니까?'), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(false), child: const Text('취소'), ), TextButton( onPressed: () => Navigator.of(context).pop(true), style: TextButton.styleFrom(foregroundColor: Colors.red), child: const Text('삭제'), ), ], ), ); if (confirmed == true) { final success = await _controller.deleteRent(rent.id!); if (success && mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('임대 계약이 삭제되었습니다')), ); } } } Future _returnRent(RentDto rent) async { final confirmed = await showDialog( context: context, builder: (context) => AlertDialog( title: const Text('장비 반납'), content: Text('ID ${rent.id}번 임대 계약의 장비를 반납 처리하시겠습니까?'), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(false), child: const Text('취소'), ), TextButton( onPressed: () => Navigator.of(context).pop(true), child: const Text('반납 처리'), ), ], ), ); if (confirmed == true) { final success = await _controller.returnRent(rent.id!); if (success && mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('장비가 반납 처리되었습니다')), ); } } } void _onStatusFilter(String? status) { _controller.setStatusFilter(status); _controller.loadRents(); } List _buildColumns() { return [ DataColumn(label: 'ID'), DataColumn(label: '장비 이력 ID'), DataColumn(label: '시작일'), DataColumn(label: '종료일'), DataColumn(label: '기간 (일)'), DataColumn(label: '상태'), DataColumn(label: '작업'), ]; } StandardDataRow _buildRow(RentDto rent, int index) { final days = _controller.calculateRentDays(rent.startedAt, rent.endedAt); final status = _controller.getRentStatus(rent); return StandardDataRow( index: index, columns: _buildColumns(), cells: [ Text(rent.id?.toString() ?? '-'), Text(rent.equipmentHistoryId.toString()), Text('${rent.startedAt.year}-${rent.startedAt.month.toString().padLeft(2, '0')}-${rent.startedAt.day.toString().padLeft(2, '0')}'), Text('${rent.endedAt.year}-${rent.endedAt.month.toString().padLeft(2, '0')}-${rent.endedAt.day.toString().padLeft(2, '0')}'), Text('$days일'), Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: _getStatusColor(status), borderRadius: BorderRadius.circular(12), ), child: Text( status, style: const TextStyle(color: Colors.white, fontSize: 12), ), ), Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( icon: const Icon(Icons.edit, size: 18), onPressed: () => _showEditDialog(rent), tooltip: '수정', ), if (status == '진행중') IconButton( icon: const Icon(Icons.assignment_return, size: 18), onPressed: () => _returnRent(rent), tooltip: '반납 처리', ), IconButton( icon: const Icon(Icons.delete, size: 18, color: Colors.red), onPressed: () => _deleteRent(rent), tooltip: '삭제', ), ], ), ], ); } Color _getStatusColor(String? status) { switch (status) { case '진행중': return Colors.blue; case '종료': return Colors.green; case '예약': return Colors.orange; default: return Colors.grey; } } Widget _buildDataTableSection(RentController controller) { // 로딩 상태 if (controller.isLoading) { return const StandardLoadingState(); } // 에러 상태 if (controller.error != null) { return StandardErrorState( message: controller.error!, onRetry: _refresh, ); } // 데이터가 없는 경우 if (controller.rents.isEmpty) { return const StandardEmptyState( message: '임대 계약이 없습니다', ); } // 데이터 테이블 return StandardDataTable( columns: _buildColumns(), rows: controller.rents .asMap() .entries .map((entry) => _buildRow(entry.value, entry.key)) .toList(), emptyWidget: const StandardEmptyState( message: '임대 계약이 없습니다', ), ); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey[50], // AppTheme 대신 직접 색상 지정 body: ChangeNotifierProvider.value( value: _controller, child: Consumer( builder: (context, controller, child) { return Column( children: [ // 액션 바 StandardActionBar( totalCount: _controller.totalRents, onRefresh: _refresh, rightActions: [ ElevatedButton.icon( onPressed: _showCreateDialog, icon: const Icon(Icons.add), label: const Text('새 임대 계약'), ), ], ), const SizedBox(height: 16), // 버튼 및 필터 섹션 (수동 구성) Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Row( children: [ // 상태 필터 SizedBox( width: 120, child: DropdownButtonFormField( value: controller.selectedStatus, decoration: const InputDecoration( labelText: '상태', border: OutlineInputBorder(), contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 8), ), items: [ const DropdownMenuItem( value: null, child: Text('전체'), ), const DropdownMenuItem( value: 'active', child: Text('진행 중'), ), const DropdownMenuItem( value: 'overdue', child: Text('연체'), ), const DropdownMenuItem( value: 'completed', child: Text('완료'), ), const DropdownMenuItem( value: 'cancelled', child: Text('취소'), ), ], onChanged: _onStatusFilter, ), ), const SizedBox(width: 8), ElevatedButton.icon( onPressed: _showCreateDialog, icon: const Icon(Icons.add), label: const Text('새 임대'), ), ], ), ), const SizedBox(height: 16), // 데이터 테이블 Expanded( child: _buildDataTableSection(controller), ), // 페이지네이션 if (controller.totalPages > 1) Padding( padding: const EdgeInsets.all(16), child: Pagination( totalCount: controller.totalRents, currentPage: controller.currentPage, pageSize: 20, onPageChanged: (page) => controller.loadRents(page: page), ), ), ], ); }, ), ), ); } }