import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:shadcn_ui/shadcn_ui.dart'; import '../../screens/equipment/controllers/equipment_history_controller.dart'; import '../../screens/equipment/controllers/equipment_list_controller.dart'; import '../../data/models/equipment_history_dto.dart'; class StockInForm extends StatefulWidget { const StockInForm({super.key}); @override State createState() => _StockInFormState(); } class _StockInFormState extends State { final _formKey = GlobalKey(); int? _selectedEquipmentId; int? _selectedWarehouseId; int _quantity = 1; DateTime _transactionDate = DateTime.now(); String? _notes; @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { // 장비 목록 로드 context.read().refresh(); }); } Future _handleSubmit() async { if (_formKey.currentState?.saveAndValidate() ?? false) { final controller = context.read(); // 백엔드 스키마에 맞는 요청 데이터 생성 final request = EquipmentHistoryRequestDto( equipmentsId: _selectedEquipmentId!, warehousesId: _selectedWarehouseId ?? 1, // 기본 창고 ID transactionType: 'I', // 입고 quantity: _quantity, transactedAt: _transactionDate, remark: _notes, ); await controller.createHistory(request); if (controller.error == null && mounted) { ShadToaster.of(context).show( const ShadToast( title: Text('입고 등록 완료'), description: Text('장비가 성공적으로 입고되었습니다'), ), ); Navigator.pop(context, true); } else if (controller.error != null && mounted) { ShadToaster.of(context).show( ShadToast.destructive( title: const Text('입고 등록 실패'), description: Text(controller.error!), ), ); } } } @override Widget build(BuildContext context) { final theme = ShadTheme.of(context); return Scaffold( backgroundColor: theme.colorScheme.background, appBar: AppBar( backgroundColor: theme.colorScheme.card, title: const Text('장비 입고 등록'), leading: IconButton( icon: const Icon(Icons.arrow_back), onPressed: () => Navigator.pop(context), ), ), body: SingleChildScrollView( padding: const EdgeInsets.all(24), child: Center( child: Container( constraints: const BoxConstraints(maxWidth: 600), child: ShadCard( child: Padding( padding: const EdgeInsets.all(24), child: ShadForm( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '입고 정보 입력', style: theme.textTheme.h3, ), const SizedBox(height: 8), Text( '입고할 장비와 창고 정보를 입력하세요', style: theme.textTheme.muted, ), const SizedBox(height: 24), // 장비 선택 Consumer( builder: (context, controller, _) { return ShadSelect( placeholder: const Text('장비 선택'), options: controller.equipments.map((equipment) { return ShadOption( value: equipment.id!, child: Text('${equipment.equipment.modelDto?.name ?? 'Unknown'} (${equipment.equipment.serialNumber})'), ); }).toList(), selectedOptionBuilder: (context, value) { final equipment = controller.equipments.firstWhere( (e) => e.id == value, ); return Text('${equipment.equipment.modelDto?.name ?? 'Unknown'} (${equipment.equipment.serialNumber})'); }, onChanged: (value) { setState(() { _selectedEquipmentId = value; }); }, ); }, ), const SizedBox(height: 16), // 창고 선택 ShadSelect( placeholder: const Text('창고 선택'), options: [ const ShadOption(value: 1, child: Text('본사 창고')), const ShadOption(value: 2, child: Text('지사 창고')), const ShadOption(value: 3, child: Text('외부 창고')), ], selectedOptionBuilder: (context, value) { switch (value) { case 1: return const Text('본사 창고'); case 2: return const Text('지사 창고'); case 3: return const Text('외부 창고'); default: return const Text(''); } }, onChanged: (value) { setState(() { _selectedWarehouseId = value; }); }, ), const SizedBox(height: 16), // 수량 ShadInputFormField( label: const Text('수량'), initialValue: '1', keyboardType: TextInputType.number, validator: (v) { if (_quantity <= 0) { return '수량은 1 이상이어야 합니다'; } return null; }, onChanged: (value) { setState(() { _quantity = int.tryParse(value) ?? 1; }); }, ), const SizedBox(height: 16), // 입고일 ShadInputFormField( label: const Text('입고일'), initialValue: '${_transactionDate.year}-${_transactionDate.month.toString().padLeft(2, '0')}-${_transactionDate.day.toString().padLeft(2, '0')}', enabled: false, trailing: IconButton( icon: const Icon(Icons.calendar_today, size: 16), onPressed: () async { final picked = await showDatePicker( context: context, initialDate: _transactionDate, firstDate: DateTime(2020), lastDate: DateTime.now(), ); if (picked != null) { setState(() { _transactionDate = picked; }); } }, ), ), const SizedBox(height: 16), // 상태 Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('상태', style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500)), const SizedBox(height: 8), ShadSelect( placeholder: const Text('상태 선택'), initialValue: 'available', options: const [ ShadOption(value: 'available', child: Text('사용 가능')), ShadOption(value: 'in_use', child: Text('사용 중')), ShadOption(value: 'maintenance', child: Text('정비 중')), ShadOption(value: 'reserved', child: Text('예약됨')), ], selectedOptionBuilder: (context, value) { switch (value) { case 'available': return const Text('사용 가능'); case 'in_use': return const Text('사용 중'); case 'maintenance': return const Text('정비 중'); case 'reserved': return const Text('예약됨'); default: return const Text(''); } }, onChanged: (value) { // 상태 변경 시 필요한 로직이 있다면 여기에 추가 }, ), ], ), const SizedBox(height: 16), // 비고 ShadInputFormField( label: const Text('비고'), maxLines: 3, placeholder: const Text('추가 정보를 입력하세요'), onChanged: (value) { _notes = value.isEmpty ? null : value; }, ), const SizedBox(height: 32), // 버튼 Row( mainAxisAlignment: MainAxisAlignment.end, children: [ ShadButton.outline( child: const Text('취소'), onPressed: () => Navigator.pop(context), ), const SizedBox(width: 8), Consumer( builder: (context, controller, _) { return ShadButton( enabled: !controller.isLoading, onPressed: _handleSubmit, child: controller.isLoading ? const SizedBox( width: 16, height: 16, child: CircularProgressIndicator( strokeWidth: 2, ), ) : const Text('입고 등록'), ); }, ), ], ), ], ), ), ), ), ), ), ), ); } }