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'; // 사용자 등록/수정 화면 (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) { return Scaffold( appBar: AppBar( title: Text(controller.isEditMode ? '사용자 수정' : '사용자 등록'), ), body: controller.isLoading ? const Center(child: ShadProgress()) : Padding( padding: const EdgeInsets.all(16.0), child: 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), const SizedBox(height: 24), // 중복 검사 상태 메시지 영역 (고정 높이) SizedBox( height: 40, child: Center( child: controller.isCheckingEmailDuplicate ? const Row( mainAxisAlignment: MainAxisAlignment.center, children: [ ShadProgress(), SizedBox(width: 8), Text('중복 검사 중...'), ], ) : controller.emailDuplicateMessage != null ? Text( controller.emailDuplicateMessage!, style: const TextStyle( color: Colors.red, fontWeight: FontWeight.bold, ), ) : Container(), ), ), // 오류 메시지 표시 if (controller.error != null) Padding( padding: const EdgeInsets.only(bottom: 16), child: ShadAlert.destructive( title: const Text('오류'), description: Text(controller.error!), ), ), // 저장 버튼 SizedBox( width: double.infinity, child: ShadButton( onPressed: controller.isLoading || controller.isCheckingEmailDuplicate ? null : () => _onSaveUser(controller), size: ShadButtonSize.lg, child: Text(controller.isEditMode ? '수정하기' : '등록하기'), ), ), ], ), ), ), ), ); }, ), ); } // 이름/직급/이메일 등 공통 텍스트 필드 위젯 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, Widget? suffixIcon, }) { 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); } }, ), ], ), ); } // 회사 선택 드롭다운 Widget _buildCompanyDropdown(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), controller.isLoadingCompanies ? const ShadProgress() : ShadSelect( selectedOptionBuilder: (context, value) { if (value == null) { return const Text('회사를 선택하세요'); } final companyName = controller.companies[value]; return Text(companyName ?? '알 수 없는 회사 (ID: $value)'); }, placeholder: const Text('회사를 선택하세요'), initialValue: controller.companiesId, options: controller.companies.entries.map((entry) { return ShadOption( value: entry.key, child: Text(entry.value), ); }).toList(), onChanged: (value) { if (value != null) { controller.companiesId = value; } }, ), ], ), ); } // 저장 버튼 클릭 시 사용자 저장 void _onSaveUser(UserFormController controller) async { // 먼저 폼 유효성 검사 if (controller.formKey.currentState?.validate() != true) { return; } // 폼 데이터 저장 controller.formKey.currentState?.save(); // 이메일 중복 검사 (저장 시점) final emailIsUnique = await controller.checkDuplicateEmail(controller.email); if (!emailIsUnique) { // 중복이 발견되면 저장하지 않음 return; } // 이메일 중복이 없으면 저장 진행 await controller.saveUser((error) { if (error != null) { ShadToaster.of(context).show( ShadToast.destructive( title: const Text('오류'), description: Text(error), ), ); } else { ShadToaster.of(context).show( ShadToast( title: const Text('성공'), description: Text( controller.isEditMode ? '사용자 정보가 수정되었습니다' : '사용자가 등록되었습니다', ), ), ); Navigator.pop(context, true); } }); } }