import 'package:flutter/material.dart'; import '../../../injection_container.dart'; import 'package:shadcn_ui/shadcn_ui.dart'; import '../../common/theme_shadcn.dart'; import '../../../domain/usecases/equipment/search_equipment_usecase.dart'; import '../../../data/models/equipment/equipment_dto.dart'; /// 장비 시리얼/바코드 검색 다이얼로그 class EquipmentSearchDialog extends StatefulWidget { final Function(EquipmentDto equipment)? onEquipmentFound; const EquipmentSearchDialog({super.key, this.onEquipmentFound}); @override State createState() => _EquipmentSearchDialogState(); } class _EquipmentSearchDialogState extends State { final _serialController = TextEditingController(); final _barcodeController = TextEditingController(); late final GetEquipmentBySerialUseCase _serialUseCase; late final GetEquipmentByBarcodeUseCase _barcodeUseCase; bool _isLoading = false; String? _errorMessage; EquipmentDto? _foundEquipment; @override void initState() { super.initState(); _serialUseCase = sl(); _barcodeUseCase = sl(); } @override void dispose() { _serialController.dispose(); _barcodeController.dispose(); super.dispose(); } Future _searchBySerial() async { final serial = _serialController.text.trim(); if (serial.isEmpty) { setState(() { _errorMessage = '시리얼 번호를 입력해주세요.'; }); return; } setState(() { _isLoading = true; _errorMessage = null; _foundEquipment = null; }); final result = await _serialUseCase(serial); result.fold( (failure) { setState(() { _errorMessage = failure.message; _isLoading = false; }); }, (equipment) { setState(() { _foundEquipment = equipment; _isLoading = false; }); }, ); } Future _searchByBarcode() async { final barcode = _barcodeController.text.trim(); if (barcode.isEmpty) { setState(() { _errorMessage = '바코드를 입력해주세요.'; }); return; } setState(() { _isLoading = true; _errorMessage = null; _foundEquipment = null; }); final result = await _barcodeUseCase(barcode); result.fold( (failure) { setState(() { _errorMessage = failure.message; _isLoading = false; }); }, (equipment) { setState(() { _foundEquipment = equipment; _isLoading = false; }); }, ); } @override Widget build(BuildContext context) { return ShadDialog( child: SizedBox( width: 500, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ // 헤더 Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('장비 검색', style: ShadcnTheme.headingH3), ShadButton.ghost( onPressed: () => Navigator.of(context).pop(), child: const Icon(Icons.close), ), ], ), const SizedBox(height: 24), // 시리얼 검색 Text('시리얼 번호로 검색', style: ShadcnTheme.bodyLarge.copyWith(fontWeight: FontWeight.w500)), const SizedBox(height: 8), Row( children: [ Expanded( child: ShadInput( controller: _serialController, placeholder: const Text('시리얼 번호 입력'), onSubmitted: (_) => _searchBySerial(), ), ), const SizedBox(width: 12), ShadButton( onPressed: _isLoading ? null : _searchBySerial, child: const Text('검색'), ), ], ), const SizedBox(height: 16), // 바코드 검색 Text('바코드로 검색', style: ShadcnTheme.bodyLarge.copyWith(fontWeight: FontWeight.w500)), const SizedBox(height: 8), Row( children: [ Expanded( child: ShadInput( controller: _barcodeController, placeholder: const Text('바코드 입력'), onSubmitted: (_) => _searchByBarcode(), ), ), const SizedBox(width: 12), ShadButton( onPressed: _isLoading ? null : _searchByBarcode, child: const Text('검색'), ), const SizedBox(width: 8), ShadButton.outline( onPressed: () => _showQRScanDialog(), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.qr_code_scanner, size: 16), const SizedBox(width: 4), const Text('QR 스캔'), ], ), ), ], ), const SizedBox(height: 24), // 로딩 표시 if (_isLoading) Center( child: Column( children: [ ShadProgress(value: null), const SizedBox(height: 8), Text('검색 중...', style: ShadcnTheme.bodyMedium), ], ), ), // 오류 메시지 if (_errorMessage != null) Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.red.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.red.withValues(alpha: 0.2)), ), child: Row( children: [ Icon(Icons.error_outline, color: Colors.red, size: 16), const SizedBox(width: 8), Expanded( child: Text( _errorMessage!, style: ShadcnTheme.bodyMedium.copyWith(color: Colors.red), ), ), ], ), ), // 검색 결과 if (_foundEquipment != null) Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.green.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.green.withValues(alpha: 0.2)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(Icons.check_circle, color: Colors.green, size: 20), const SizedBox(width: 8), Text( '장비를 찾았습니다!', style: ShadcnTheme.bodyLarge.copyWith( color: Colors.green, fontWeight: FontWeight.w500, ), ), ], ), const SizedBox(height: 12), _buildEquipmentInfo(_foundEquipment!), const SizedBox(height: 16), Row( mainAxisAlignment: MainAxisAlignment.end, children: [ ShadButton.outline( onPressed: () => Navigator.of(context).pop(), child: const Text('닫기'), ), const SizedBox(width: 8), ShadButton( onPressed: () { if (widget.onEquipmentFound != null) { widget.onEquipmentFound!(_foundEquipment!); } Navigator.of(context).pop(); }, child: const Text('선택'), ), ], ), ], ), ), const SizedBox(height: 16), ], ), ), ); } /// 장비 정보 표시 Widget _buildEquipmentInfo(EquipmentDto equipment) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildInfoRow('시리얼 번호', equipment.serialNumber), if (equipment.barcode != null) _buildInfoRow('바코드', equipment.barcode!), if (equipment.modelName != null) _buildInfoRow('모델명', equipment.modelName!), if (equipment.companyName != null) _buildInfoRow('소속 회사', equipment.companyName!), _buildInfoRow('활성 상태', equipment.isActive ? '활성' : '비활성'), ], ); } Widget _buildInfoRow(String label, String value) { return Padding( padding: const EdgeInsets.symmetric(vertical: 2), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( width: 80, child: Text( '$label:', style: ShadcnTheme.bodySmall.copyWith( color: ShadcnTheme.foregroundMuted, ), ), ), Expanded( child: Text( value, style: ShadcnTheme.bodySmall.copyWith( fontWeight: FontWeight.w500, ), ), ), ], ), ); } /// QR 스캔 다이얼로그 (임시 구현) void _showQRScanDialog() { showDialog( context: context, builder: (context) => ShadDialog( child: SizedBox( width: 300, child: Column( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.qr_code_scanner, size: 64, color: ShadcnTheme.primary), const SizedBox(height: 16), Text( 'QR 스캔 기능', style: ShadcnTheme.headingH3, ), const SizedBox(height: 8), Text( 'QR 스캔 기능은 추후 구현 예정입니다.', style: ShadcnTheme.bodyMedium.copyWith( color: ShadcnTheme.foregroundMuted, ), textAlign: TextAlign.center, ), const SizedBox(height: 24), ShadButton( onPressed: () => Navigator.of(context).pop(), child: const Text('확인'), ), ], ), ), ), ); } } /// 장비 검색 다이얼로그 표시 유틸리티 Future showEquipmentSearchDialog( BuildContext context, { Function(EquipmentDto equipment)? onEquipmentFound, }) async { return await showDialog( context: context, barrierDismissible: false, builder: (context) => EquipmentSearchDialog( onEquipmentFound: onEquipmentFound, ), ); }