import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:superport/screens/common/theme_shadcn.dart'; import 'package:superport/utils/constants.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'; // 사용자 등록/수정 화면 (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: CircularProgressIndicator()) : 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: CircularProgressIndicator( strokeWidth: 2, ), ), ) : 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) ...[ ExpansionTile( title: const Text('비밀번호 변경'), 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) Container( padding: const EdgeInsets.all(12), margin: const EdgeInsets.only(bottom: 16), decoration: BoxDecoration( color: Colors.red.shade50, borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.red.shade200), ), child: Row( children: [ Icon(Icons.error_outline, color: Colors.red.shade700), const SizedBox(width: 8), Expanded( child: Text( controller.error!, style: TextStyle(color: Colors.red.shade700), ), ), ], ), ), // 저장 버튼 SizedBox( width: double.infinity, child: ElevatedButton( onPressed: controller.isLoading ? null : () => _onSaveUser(controller), style: ElevatedButton.styleFrom( backgroundColor: ShadcnTheme.primary, foregroundColor: Colors.white, ), child: Padding( padding: const EdgeInsets.all(12.0), child: controller.isLoading ? const SizedBox( height: 20, width: 20, child: CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation(Colors.white), ), ) : Text( controller.isEditMode ? '수정하기' : '등록하기', style: const TextStyle(fontSize: 16), ), ), ), ), ], ), ), ), ), ); }, ), ); } // 이름/직급/이메일 등 공통 텍스트 필드 위젯 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, }) { 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), TextFormField( initialValue: initialValue, decoration: InputDecoration( hintText: hintText, suffixIcon: suffixIcon, ), 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), TextFormField( controller: controller, obscureText: obscureText, decoration: InputDecoration( hintText: hintText, suffixIcon: IconButton( icon: Icon( obscureText ? Icons.visibility : Icons.visibility_off, ), onPressed: onToggleVisibility, ), ), 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), Row( children: [ // 접두사 드롭다운 (010, 02, 031 등) Container( padding: const EdgeInsets.symmetric(horizontal: 12), decoration: BoxDecoration( border: Border.all(color: Colors.grey), borderRadius: BorderRadius.circular(4), ), child: DropdownButton( value: controller.phonePrefix, items: controller.phonePrefixes.map((prefix) { return DropdownMenuItem( value: prefix, child: Text(prefix), ); }).toList(), onChanged: (value) { if (value != null) { controller.updatePhonePrefix(value); } }, underline: Container(), // 밑줄 제거 ), ), const SizedBox(width: 8), const Text('-', style: TextStyle(fontSize: 16)), const SizedBox(width: 8), // 전화번호 입력 (7-8자리) Expanded( child: TextFormField( initialValue: controller.phoneNumber, decoration: const InputDecoration( hintText: '1234567 또는 12345678', border: OutlineInputBorder(), ), keyboardType: TextInputType.phone, inputFormatters: [ FilteringTextInputFormatter.digitsOnly, LengthLimitingTextInputFormatter(8), ], validator: (value) { if (value != null && value.isNotEmpty) { if (value.length < 7 || value.length > 8) { return '전화번호는 7-8자리 숫자를 입력해주세요'; } } return null; }, onChanged: (value) { controller.updatePhoneNumber(value); }, onSaved: (value) { if (value != null) { controller.updatePhoneNumber(value); } }, ), ), ], ), if (controller.combinedPhoneNumber.isNotEmpty) Padding( padding: const EdgeInsets.only(top: 4), child: Text( '전화번호: ${controller.combinedPhoneNumber}', style: TextStyle( fontSize: 12, color: Colors.grey[600], ), ), ), ], ), ); } // 권한 드롭다운 (새 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), DropdownButtonFormField( value: controller.role, decoration: const InputDecoration( hintText: '권한을 선택하세요', border: OutlineInputBorder(), ), items: UserRole.values.map((role) { return DropdownMenuItem( value: role, child: Text(role.displayName), ); }).toList(), onChanged: (value) { if (value != null) { controller.role = value; } }, validator: (value) { if (value == null) { return '권한을 선택해주세요'; } return null; }, ), 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) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(error), backgroundColor: Colors.red, ), ); } else { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(controller.isEditMode ? '사용자 정보가 수정되었습니다' : '사용자가 등록되었습니다'), backgroundColor: Colors.green, ), ); Navigator.pop(context, true); } }); } }