Files
superport/lib/screens/user/controllers/user_form_controller.dart
JiWoong Sul 1e6da44917
Some checks failed
Flutter Test & Quality Check / Build APK (push) Has been cancelled
Flutter Test & Quality Check / Test on macos-latest (push) Has been cancelled
Flutter Test & Quality Check / Test on ubuntu-latest (push) Has been cancelled
refactor: UI 화면 통합 및 불필요한 파일 정리
- 모든 *_redesign.dart 파일을 기본 화면 파일로 통합
- 백업용 컨트롤러 파일들 제거 (*_controller.backup.dart)
- 사용하지 않는 예제 및 테스트 파일 제거
- Clean Architecture 적용 후 남은 정리 작업 완료
- 테스트 코드 정리 및 구조 개선 준비

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-11 14:00:44 +09:00

272 lines
7.2 KiB
Dart

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'package:superport/models/company_model.dart';
import 'package:superport/models/user_model.dart';
import 'package:superport/services/user_service.dart';
import 'package:superport/services/company_service.dart';
import 'package:superport/utils/constants.dart';
import 'package:superport/models/user_phone_field.dart';
// 사용자 폼의 상태 및 비즈니스 로직을 담당하는 컨트롤러
class UserFormController extends ChangeNotifier {
final UserService _userService = GetIt.instance<UserService>();
final CompanyService _companyService = GetIt.instance<CompanyService>();
final GlobalKey<FormState> formKey = GlobalKey<FormState>();
// 상태 변수
bool _isLoading = false;
String? _error;
// API만 사용
// 폼 필드
bool isEditMode = false;
int? userId;
String name = '';
String username = ''; // 추가
String password = ''; // 추가
int? companyId;
int? branchId;
String role = UserRoles.member;
String position = '';
String email = '';
// username 중복 확인
bool _isCheckingUsername = false;
bool? _isUsernameAvailable;
String? _lastCheckedUsername;
Timer? _usernameCheckTimer;
// 전화번호 관련 상태
final List<UserPhoneField> phoneFields = [];
final List<String> phoneTypes = ['휴대폰', '사무실', '팩스', '기타'];
List<Company> companies = [];
List<Branch> branches = [];
// Getters
bool get isLoading => _isLoading;
String? get error => _error;
bool get isCheckingUsername => _isCheckingUsername;
bool? get isUsernameAvailable => _isUsernameAvailable;
UserFormController({this.userId}) {
isEditMode = userId != null;
if (isEditMode) {
loadUser();
} else {
addPhoneField();
}
loadCompanies();
}
// 회사 목록 로드
Future<void> loadCompanies() async {
try {
final result = await _companyService.getCompanies();
companies = result.items; // PaginatedResponse에서 items 추출
notifyListeners();
} catch (e) {
debugPrint('회사 목록 로드 실패: $e');
companies = [];
notifyListeners();
}
}
// 회사 ID에 따라 지점 목록 로드
void loadBranches(int companyId) {
final company = companies.firstWhere(
(c) => c.id == companyId,
orElse: () => Company(
id: companyId,
name: '알 수 없는 회사',
branches: [],
),
);
branches = company.branches ?? [];
// 지점 변경 시 이전 선택 지점이 새 회사에 없으면 초기화
if (branchId != null && !branches.any((b) => b.id == branchId)) {
branchId = null;
}
notifyListeners();
}
// 사용자 정보 로드 (수정 모드)
Future<void> loadUser() async {
if (userId == null) return;
_isLoading = true;
_error = null;
notifyListeners();
try {
final user = await _userService.getUser(userId!);
if (user != null) {
name = user.name;
username = user.username ?? '';
companyId = user.companyId;
branchId = user.branchId;
role = user.role;
position = user.position ?? '';
email = user.email ?? '';
if (companyId != null) {
loadBranches(companyId!);
}
phoneFields.clear();
if (user.phoneNumbers.isNotEmpty) {
for (var phone in user.phoneNumbers) {
phoneFields.add(
UserPhoneField(
type: phone['type'] ?? '휴대폰',
initialValue: phone['number'] ?? '',
),
);
}
} else {
addPhoneField();
}
}
} catch (e) {
_error = e.toString();
} finally {
_isLoading = false;
notifyListeners();
}
}
// 전화번호 필드 추가
void addPhoneField() {
phoneFields.add(UserPhoneField(type: '휴대폰'));
notifyListeners();
}
// 전화번호 필드 삭제
void removePhoneField(int index) {
if (phoneFields.length > 1) {
phoneFields[index].dispose();
phoneFields.removeAt(index);
notifyListeners();
}
}
// Username 중복 확인
void checkUsernameAvailability(String value) {
if (value.isEmpty || value == _lastCheckedUsername) {
return;
}
// 디바운싱
_usernameCheckTimer?.cancel();
_usernameCheckTimer = Timer(const Duration(milliseconds: 500), () async {
_isCheckingUsername = true;
notifyListeners();
try {
final isDuplicate = await _userService.checkDuplicateUsername(value);
_isUsernameAvailable = !isDuplicate;
_lastCheckedUsername = value;
} catch (e) {
_isUsernameAvailable = null;
} finally {
_isCheckingUsername = false;
notifyListeners();
}
});
}
// 사용자 저장 (UI에서 호출)
Future<void> saveUser(Function(String? error) onResult) async {
if (formKey.currentState?.validate() != true) {
onResult('폼 유효성 검사 실패');
return;
}
formKey.currentState?.save();
if (companyId == null) {
onResult('소속 회사를 선택해주세요');
return;
}
// 신규 등록 시 username 중복 확인
if (!isEditMode) {
if (username.isEmpty) {
onResult('사용자명을 입력해주세요');
return;
}
if (_isUsernameAvailable == false) {
onResult('이미 사용중인 사용자명입니다');
return;
}
if (password.isEmpty) {
onResult('비밀번호를 입력해주세요');
return;
}
}
_isLoading = true;
_error = null;
notifyListeners();
try {
// 전화번호 목록 준비
String? phoneNumber;
for (var phoneField in phoneFields) {
if (phoneField.number.isNotEmpty) {
phoneNumber = phoneField.number;
break; // API는 단일 전화번호만 지원
}
}
if (isEditMode && userId != null) {
// 사용자 수정
await _userService.updateUser(
userId!,
name: name,
email: email.isNotEmpty ? email : null,
phone: phoneNumber,
companyId: companyId,
branchId: branchId,
role: role,
position: position.isNotEmpty ? position : null,
password: password.isNotEmpty ? password : null,
);
} else {
// 사용자 생성
await _userService.createUser(
username: username,
email: email,
password: password,
name: name,
role: role,
companyId: companyId!,
branchId: branchId,
phone: phoneNumber,
position: position.isNotEmpty ? position : null,
);
}
onResult(null);
} catch (e) {
_error = e.toString();
onResult(_error);
} finally {
_isLoading = false;
notifyListeners();
}
}
// 컨트롤러 해제
@override
void dispose() {
_usernameCheckTimer?.cancel();
for (var phoneField in phoneFields) {
phoneField.dispose();
}
super.dispose();
}
// API 모드만 사용 (Mock 데이터 제거됨)
// void toggleApiMode() 메서드 제거
}