import 'package:flutter/material.dart'; import 'package:shadcn_ui/shadcn_ui.dart'; import 'package:provider/provider.dart'; import 'package:get_it/get_it.dart'; import 'package:superport/screens/common/widgets/remark_input.dart'; import 'package:superport/screens/common/templates/form_layout_template.dart'; import 'controllers/warehouse_location_form_controller.dart'; import 'package:superport/data/models/zipcode_dto.dart'; import 'package:superport/screens/zipcode/zipcode_search_screen.dart'; import 'package:superport/screens/zipcode/controllers/zipcode_controller.dart'; import 'package:superport/domain/usecases/zipcode_usecase.dart'; /// 입고지 추가/수정 폼 화면 (SRP 적용, 상태/로직 분리) class WarehouseLocationFormScreen extends StatefulWidget { final int? id; // 수정 모드 지원을 위한 id 파라미터 final Map? preloadedData; // 사전 로드된 데이터 const WarehouseLocationFormScreen({super.key, this.id, this.preloadedData}); @override State createState() => _WarehouseLocationFormScreenState(); } class _WarehouseLocationFormScreenState extends State { /// 폼 컨트롤러 (상태 및 저장/수정 로직 위임) late final WarehouseLocationFormController _controller; /// 상태 메시지 String? _statusMessage; /// 저장 중 여부 bool _isSaving = false; @override void initState() { super.initState(); // 컨트롤러 생성 및 초기화 if (widget.preloadedData != null) { // 사전 로드된 데이터로 즉시 초기화 _controller = WarehouseLocationFormController.withPreloadedData( preloadedData: widget.preloadedData!, ); } else { _controller = WarehouseLocationFormController(); if (widget.id != null) { // 비동기 초기화를 위해 addPostFrameCallback 사용 WidgetsBinding.instance.addPostFrameCallback((_) { _controller.initialize(widget.id!); }); } } } @override void dispose() { // 컨트롤러 해제 _controller.dispose(); super.dispose(); } // 우편번호 검색 다이얼로그 Future _showZipcodeSearchDialog() async { return await showDialog( context: context, barrierDismissible: true, builder: (BuildContext dialogContext) => Dialog( clipBehavior: Clip.none, insetPadding: const EdgeInsets.symmetric(horizontal: 40, vertical: 24), child: SizedBox( width: 800, height: 600, child: Container( decoration: BoxDecoration( color: ShadTheme.of(context).colorScheme.background, borderRadius: BorderRadius.circular(8), ), child: ChangeNotifierProvider( create: (_) => ZipcodeController( GetIt.instance(), ), child: ZipcodeSearchScreen( onSelect: (zipcode) { Navigator.of(dialogContext).pop(zipcode); }, ), ), ), ), ), ); } // 저장 메소드 Future _onSave() async { // 폼 유효성 검사 if (!_controller.formKey.currentState!.validate()) { return; } setState(() { _isSaving = true; _statusMessage = '중복 확인 중...'; }); // 저장 시 중복 검사 수행 final name = _controller.nameController.text.trim(); final isDuplicate = await _controller.checkDuplicateName( name, excludeId: _controller.isEditMode ? _controller.id : null, ); if (isDuplicate) { setState(() { _isSaving = false; _statusMessage = '이미 존재하는 창고명입니다.'; }); return; } setState(() { _statusMessage = '저장 중...'; }); final success = await _controller.save(); setState(() { _isSaving = false; _statusMessage = null; }); if (success) { // 성공 메시지 표시 if (mounted) { ShadToaster.of(context).show( ShadToast( title: const Text('성공'), description: Text(_controller.isEditMode ? '입고지가 수정되었습니다' : '입고지가 추가되었습니다'), ), ); // 리스트 화면으로 돌아가기 Navigator.of(context).pop(true); } } else { // 실패 메시지 표시 if (mounted) { ShadToaster.of(context).show( ShadToast.destructive( title: const Text('오류'), description: Text(_controller.error ?? '저장에 실패했습니다'), ), ); } } } @override Widget build(BuildContext context) { return FormLayoutTemplate( title: _controller.isEditMode ? '입고지 수정' : '입고지 추가', onSave: _isSaving ? null : _onSave, saveButtonText: '저장', isLoading: _isSaving, child: Form( key: _controller.formKey, child: SingleChildScrollView( padding: const EdgeInsets.all(UIConstants.formPadding), child: FormSection( title: '창고 정보', subtitle: '창고의 기본 정보를 입력하세요', children: [ // 입고지명 입력 FormFieldWrapper( label: '창고명', required: true, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ ShadInputFormField( controller: _controller.nameController, placeholder: const Text('창고명을 입력하세요'), validator: (value) { if (value.trim().isEmpty) { return '창고명을 입력하세요'; } return null; }, ), // 상태 메시지 영역 (고정 높이) SizedBox( height: 20, child: _statusMessage != null ? Padding( padding: const EdgeInsets.only(top: 4), child: Text( _statusMessage!, style: TextStyle( fontSize: 12, color: _statusMessage!.contains('존재') ? Colors.red : Colors.grey, ), ), ) : const SizedBox.shrink(), ), ], ), ), // 우편번호 검색 FormFieldWrapper( label: '우편번호', child: Row( children: [ Expanded( child: ShadInputFormField( controller: _controller.zipcodeController, placeholder: const Text('우편번호'), readOnly: true, ), ), const SizedBox(width: 8), ShadButton( onPressed: () async { // 우편번호 검색 다이얼로그 호출 final result = await _showZipcodeSearchDialog(); if (result != null) { _controller.selectZipcode(result); } }, child: const Text('검색'), ), ], ), ), // 주소 입력 (단일 필드) FormFieldWrapper( label: '주소', child: ShadInputFormField( controller: _controller.addressController, placeholder: const Text('상세 주소를 입력하세요'), maxLines: 2, ), ), // 비고 입력 FormFieldWrapper( label: '비고', child: RemarkInput(controller: _controller.remarkController), ), ], ), ), ), ); } }