import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:shadcn_ui/shadcn_ui.dart'; import 'package:superport/utils/validators.dart'; import 'package:flutter/services.dart'; import 'package:superport/screens/user/controllers/user_form_controller.dart'; import 'package:superport/utils/formatters/korean_phone_formatter.dart'; import 'package:superport/screens/common/widgets/standard_dropdown.dart'; import 'package:superport/screens/common/templates/form_layout_template.dart'; // 사용자 등록/수정 화면 (UI만 담당, 상태/로직 분리) class UserFormScreen extends StatefulWidget { final int? userId; const UserFormScreen({super.key, this.userId}); @override State createState() => _UserFormScreenState(); } class _UserFormScreenState extends State { @override void dispose() { super.dispose(); } @override Widget build(BuildContext context) { return ChangeNotifierProvider( create: (_) { final controller = UserFormController( userId: widget.userId, ); // 비동기 초기화 호출 if (widget.userId != null) { WidgetsBinding.instance.addPostFrameCallback((_) { controller.initialize(); }); } return controller; }, child: Consumer( builder: (context, controller, child) { // Phase 10: FormLayoutTemplate 적용 return FormLayoutTemplate( title: controller.isEditMode ? '사용자 수정' : '사용자 등록', isLoading: controller.isLoading, onSave: () async { // 폼 검증 if (!controller.formKey.currentState!.validate()) { return; } controller.formKey.currentState!.save(); // 사용자 저장 bool success = false; await controller.saveUser((error) { if (error == null) { success = true; } else { // 에러 처리는 controller에서 관리 } }); if (success && mounted) { Navigator.of(context).pop(true); } }, onCancel: () => Navigator.of(context).pop(), child: controller.isLoading ? const Center(child: ShadProgress()) : Form( key: controller.formKey, child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 이름 (*필수) _buildTextField( label: '이름 *', initialValue: controller.name, hintText: '사용자 이름을 입력하세요', validator: (value) => validateRequired(value, '이름'), onSaved: (value) => controller.name = value!, ), // 이메일 (선택) _buildTextField( label: '이메일', initialValue: controller.email, hintText: '이메일을 입력하세요 (선택사항)', keyboardType: TextInputType.emailAddress, validator: (value) { if (value != null && value.isNotEmpty) { return validateEmail(value); } return null; }, onSaved: (value) => controller.email = value ?? '', ), // 전화번호 (선택) _buildPhoneNumberSection(controller), // 회사 선택 (*필수) _buildCompanyDropdown(controller), // 중복 검사 상태 메시지 영역 if (controller.isCheckingEmailDuplicate) const Padding( padding: EdgeInsets.symmetric(vertical: 16), child: Center( child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ ShadProgress(), SizedBox(width: 8), Text('중복 검사 중...'), ], ), ), ), if (controller.emailDuplicateMessage != null) Padding( padding: const EdgeInsets.symmetric(vertical: 16), child: Center( child: Text( controller.emailDuplicateMessage!, style: const TextStyle( color: Colors.red, fontWeight: FontWeight.bold, ), ), ), ), // 오류 메시지 표시 if (controller.error != null) Padding( padding: const EdgeInsets.only(bottom: 16), child: ShadAlert.destructive( title: const Text('오류'), description: Text(controller.error!), ), ), ], ), ), ), ); }, ), ); } // 이름/직급/이메일 등 공통 텍스트 필드 위젯 Widget _buildTextField({ required String label, required String initialValue, required String hintText, TextInputType? keyboardType, List? inputFormatters, String? Function(String?)? validator, void Function(String?)? onSaved, void Function(String)? onChanged, }) { final controller = TextEditingController(text: initialValue.isNotEmpty ? initialValue : ''); return Padding( padding: const EdgeInsets.only(bottom: 16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(label, style: const TextStyle(fontWeight: FontWeight.bold)), const SizedBox(height: 4), ShadInputFormField( controller: controller, placeholder: Text(hintText), keyboardType: keyboardType, inputFormatters: inputFormatters, validator: validator, onSaved: onSaved, onChanged: onChanged, ), ], ), ); } // 전화번호 입력 섹션 (통합 입력 필드) Widget _buildPhoneNumberSection(UserFormController controller) { return Padding( padding: const EdgeInsets.only(bottom: 16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('전화번호', style: TextStyle(fontWeight: FontWeight.bold)), const SizedBox(height: 4), ShadInputFormField( controller: TextEditingController(text: controller.combinedPhoneNumber ?? ''), placeholder: const Text('010-1234-5678'), keyboardType: TextInputType.phone, inputFormatters: [ KoreanPhoneFormatter(), // 한국식 전화번호 자동 포맷팅 ], validator: (value) { if (value.isNotEmpty) { return PhoneValidator.validate(value); } return null; // 선택 필드이므로 비어있어도 OK }, onChanged: (value) { controller.updatePhoneNumber(value); }, onSaved: (value) { if (value != null) { controller.updatePhoneNumber(value); } }, ), ], ), ); } // 회사 선택 드롭다운 (StandardDropdown 사용) Widget _buildCompanyDropdown(UserFormController controller) { return Padding( padding: const EdgeInsets.only(bottom: 16.0), child: StandardIntDropdown>( label: '회사', isRequired: true, items: controller.companies.entries.toList(), isLoading: controller.isLoadingCompanies, error: controller.companiesError, onRetry: () => controller.retryLoadCompanies(), selectedValue: controller.companiesId != null ? controller.companies.entries .where((entry) => entry.key == controller.companiesId) .firstOrNull : null, onChanged: (MapEntry? selectedCompany) { controller.companiesId = selectedCompany?.key; }, itemBuilder: (MapEntry company) => Text(company.value), selectedItemBuilder: (MapEntry company) => Text(company.value), idExtractor: (MapEntry company) => company.key, placeholder: '회사를 선택하세요', validator: (MapEntry? value) { if (value == null) { return '회사를 선택해 주세요'; } return null; }, ), ); } }