import 'package:flutter/material.dart'; import 'package:shadcn_ui/shadcn_ui.dart'; import 'package:superport/data/models/model_dto.dart'; import 'package:superport/data/models/vendor_dto.dart'; import 'package:superport/screens/model/controllers/model_controller.dart'; /// Vendor → Model 캐스케이드 선택 컴포넌트 /// Equipment 등의 화면에서 재사용 가능 class ModelVendorCascade extends StatefulWidget { final ModelController controller; final int? initialVendorId; final int? initialModelId; final void Function(int? vendorId, int? modelId)? onChanged; final bool isRequired; const ModelVendorCascade({ super.key, required this.controller, this.initialVendorId, this.initialModelId, this.onChanged, this.isRequired = true, }); @override State createState() => _ModelVendorCascadeState(); } class _ModelVendorCascadeState extends State { int? _selectedVendorId; int? _selectedModelId; List _availableModels = []; bool _isLoadingModels = false; @override void initState() { super.initState(); _selectedVendorId = widget.initialVendorId; _selectedModelId = widget.initialModelId; // 초기 vendor가 있으면 모델 로드 if (_selectedVendorId != null) { _loadModelsForVendor(_selectedVendorId!); } } Future _loadModelsForVendor(int vendorId) async { setState(() { _isLoadingModels = true; }); try { // Controller에서 해당 vendor의 모델 가져오기 final models = widget.controller.getModelsByVendor(vendorId); setState(() { _availableModels = models; // 선택된 모델이 새 vendor의 모델 목록에 없으면 초기화 if (_selectedModelId != null && !models.any((m) => m.id == _selectedModelId)) { _selectedModelId = null; } }); } finally { setState(() { _isLoadingModels = false; }); } } @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Vendor 선택 _buildVendorSelect(), const SizedBox(height: 16), // Model 선택 (Vendor가 선택된 경우에만 표시) if (_selectedVendorId != null) _buildModelSelect(), ], ); } Widget _buildVendorSelect() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Text( '제조사', style: Theme.of(context).textTheme.bodyMedium?.copyWith( fontWeight: FontWeight.w500, ), ), if (widget.isRequired) const Text( ' *', style: TextStyle(color: Colors.red), ), ], ), const SizedBox(height: 8), ShadSelect( placeholder: const Text('제조사를 선택하세요'), options: [ if (!widget.isRequired) const ShadOption( value: null, child: Text('선택 안함'), ), ...widget.controller.vendors.map( (vendor) => ShadOption( value: vendor.id, child: Text(vendor.name), ), ), ], selectedOptionBuilder: (context, value) { if (value == null) { return const Text('선택 안함'); } final vendor = widget.controller.vendors.firstWhere( (v) => v.id == value, orElse: () => const VendorDto( name: 'Unknown', ), ); return Text(vendor.name); }, onChanged: (value) { setState(() { _selectedVendorId = value; _selectedModelId = null; // Vendor 변경 시 Model 초기화 _availableModels.clear(); }); if (value != null) { _loadModelsForVendor(value); } // 콜백 호출 widget.onChanged?.call(value, null); }, initialValue: _selectedVendorId, ), ], ); } Widget _buildModelSelect() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Text( '모델', style: Theme.of(context).textTheme.bodyMedium?.copyWith( fontWeight: FontWeight.w500, ), ), if (widget.isRequired) const Text( ' *', style: TextStyle(color: Colors.red), ), ], ), const SizedBox(height: 8), if (_isLoadingModels) const ShadInput( placeholder: Text('모델 로딩 중...'), enabled: false, ) else if (_availableModels.isEmpty) const ShadInput( placeholder: Text('해당 제조사에 등록된 모델이 없습니다'), enabled: false, ) else ShadSelect( placeholder: const Text('모델을 선택하세요'), options: [ if (!widget.isRequired) const ShadOption( value: null, child: Text('선택 안함'), ), ..._availableModels.map( (model) => ShadOption( value: model.id, child: Text(model.name), ), ), ], selectedOptionBuilder: (context, value) { if (value == null) { return const Text('선택 안함'); } final model = _availableModels.firstWhere( (m) => m.id == value, orElse: () => ModelDto( id: value, vendorsId: _selectedVendorId!, name: 'Unknown', ), ); return Text(model.name); }, onChanged: (value) { setState(() { _selectedModelId = value; }); // 콜백 호출 widget.onChanged?.call(_selectedVendorId, value); }, initialValue: _selectedModelId, ), ], ); } }