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/models/user_model.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 { final TextEditingController _passwordController = TextEditingController(); final TextEditingController _confirmPasswordController = TextEditingController(); bool _showPassword = false; bool _showConfirmPassword = false; @override void dispose() { _passwordController.dispose(); _confirmPasswordController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return ChangeNotifierProvider( create: (_) => UserFormController( userId: widget.userId, ), 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!, ), // 사용자명 (신규 등록 시만) if (!controller.isEditMode) ...[ _buildTextField( label: '사용자명 *', initialValue: controller.username, hintText: '로그인에 사용할 사용자명 (3자 이상)', validator: (value) { if (value == null || value.isEmpty) { return '사용자명을 입력해주세요'; } if (value.length < 3) { return '사용자명은 3자 이상이어야 합니다'; } if (controller.isUsernameAvailable == false) { return '이미 사용 중인 사용자명입니다'; } return null; }, onChanged: (value) { controller.username = value; controller.checkUsernameAvailability(value); }, onSaved: (value) => controller.username = value!, suffixIcon: controller.isCheckingUsername ? const SizedBox( width: 20, height: 20, child: Padding( padding: EdgeInsets.all(12.0), child: ShadProgress(), ), ) : controller.isUsernameAvailable != null ? Icon( controller.isUsernameAvailable! ? Icons.check_circle : Icons.cancel, color: controller.isUsernameAvailable! ? Colors.green : Colors.red, ) : null, ), // 비밀번호 (*필수) _buildPasswordField( label: '비밀번호 *', controller: _passwordController, hintText: '비밀번호를 입력하세요 (6자 이상)', obscureText: !_showPassword, onToggleVisibility: () { setState(() { _showPassword = !_showPassword; }); }, validator: (value) { if (value == null || value.isEmpty) { return '비밀번호를 입력해주세요'; } if (value.length < 6) { return '비밀번호는 6자 이상이어야 합니다'; } return null; }, onSaved: (value) => controller.password = value!, ), // 비밀번호 확인 _buildPasswordField( label: '비밀번호 확인', controller: _confirmPasswordController, hintText: '비밀번호를 다시 입력하세요', obscureText: !_showConfirmPassword, onToggleVisibility: () { setState(() { _showConfirmPassword = !_showConfirmPassword; }); }, validator: (value) { if (value == null || value.isEmpty) { return '비밀번호를 다시 입력해주세요'; } if (value != _passwordController.text) { return '비밀번호가 일치하지 않습니다'; } return null; }, ), ], // 수정 모드에서 비밀번호 변경 (선택사항) if (controller.isEditMode) ...[ ShadAccordion( children: [ ShadAccordionItem( value: 1, title: const Text('비밀번호 변경'), child: Column( children: [ _buildPasswordField( label: '새 비밀번호', controller: _passwordController, hintText: '변경할 경우만 입력하세요', obscureText: !_showPassword, onToggleVisibility: () { setState(() { _showPassword = !_showPassword; }); }, validator: (value) { if (value != null && value.isNotEmpty && value.length < 6) { return '비밀번호는 6자 이상이어야 합니다'; } return null; }, onSaved: (value) => controller.password = value ?? '', ), _buildPasswordField( label: '새 비밀번호 확인', controller: _confirmPasswordController, hintText: '비밀번호를 다시 입력하세요', obscureText: !_showConfirmPassword, onToggleVisibility: () { setState(() { _showConfirmPassword = !_showConfirmPassword; }); }, validator: (value) { if (_passwordController.text.isNotEmpty && value != _passwordController.text) { return '비밀번호가 일치하지 않습니다'; } return null; }, ), ], ), ), ], ), ], // 이메일 (*필수) _buildTextField( label: '이메일 *', initialValue: controller.email, hintText: '이메일을 입력하세요', keyboardType: TextInputType.emailAddress, validator: (value) { if (value == null || value.isEmpty) { return '이메일을 입력해주세요'; } return validateEmail(value); }, onSaved: (value) => controller.email = value!, ), // 전화번호 (선택) _buildPhoneNumberSection(controller), // 권한 (*필수) _buildRoleDropdown(controller), const SizedBox(height: 24), // 오류 메시지 표시 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 ? 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); 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 _buildPasswordField({ required String label, required TextEditingController controller, required String hintText, required bool obscureText, required VoidCallback onToggleVisibility, String? Function(String?)? validator, void Function(String?)? onSaved, }) { 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, obscureText: obscureText, placeholder: Text(hintText), validator: validator, onSaved: onSaved, ), ], ), ); } // 전화번호 입력 섹션 (통합 입력 필드) 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); } }, ), ], ), ); } // 권한 드롭다운 (새 UserRole 시스템) Widget _buildRoleDropdown(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), ShadSelect( selectedOptionBuilder: (context, value) => Text(value.displayName ?? ''), placeholder: const Text('권한을 선택하세요'), options: UserRole.values.map((role) { return ShadOption( value: role, child: Text(role.displayName), ); }).toList(), onChanged: (value) { if (value != null) { controller.role = value; } }, ), const SizedBox(height: 4), Text( '권한 설명:\n' '• 관리자: 전체 시스템 관리 및 모든 기능 접근\n' '• 매니저: 중간 관리 기능 및 승인 권한\n' '• 직원: 기본 사용 기능만 접근 가능', style: TextStyle( fontSize: 12, color: Colors.grey[600], ), ), ], ), ); } // 저장 버튼 클릭 시 사용자 저장 void _onSaveUser(UserFormController controller) async { 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); } }); } }