이벤트 가져오기 위젯 테스트 추가 및 테스트 훅 도입

This commit is contained in:
2025-09-12 06:33:44 +09:00
parent 107abc963f
commit a5f2544d11
121 changed files with 39277 additions and 3911 deletions
+74 -14
View File
@@ -16,12 +16,12 @@ class EventService with ChangeNotifier {
List<Team> _teams = [];
bool _isLoading = false;
String? _token;
ApiService _apiService;
final ApiService _apiService;
String? _clubId;
// 기본 생성자
EventService() : _apiService = ApiService();
// 테스트용 생성자
EventService.forTest(this._apiService);
@@ -210,12 +210,23 @@ class EventService with ChangeNotifier {
notifyListeners();
try {
// userId는 일부 라우트에서 필수이므로 prefs에서 읽어 포함
final prefs = await SharedPreferences.getInstance();
final userId = prefs.getString(ApiConfig.userIdKey);
final payload = {
'clubId': _clubId,
if (userId != null) 'userId': userId,
'eventId': eventId,
};
final data = await _apiService.post(
'${ApiConfig.clubs}/events/participants',
data: {'eventId': eventId},
'${ApiConfig.clubs}/events/$eventId/participants/list',
data: payload,
);
final List<dynamic> participantsData = data['participants'] ?? [];
// 응답이 리스트이거나 객체 내 participants 키로 올 수 있어 모두 처리
final List<dynamic> participantsData = (data is List)
? data
: (data['participants'] ?? []);
_participants = participantsData
.map((participantData) => Participant.fromJson(participantData))
.toList();
@@ -244,9 +255,12 @@ class EventService with ChangeNotifier {
notifyListeners();
try {
// 참가자 페이로드 정규화: 상태/결제 상태 표준화 및 빈 문자열 null 처리
final normalized = _sanitizeParticipantPayload(participantData);
final payload = {'clubId': _clubId, ...normalized};
final data = await _apiService.post(
'${ApiConfig.clubs}/events/$eventId/participants',
data: participantData,
data: payload,
);
final newParticipant = Participant.fromJson(data['participant']);
@@ -278,9 +292,11 @@ class EventService with ChangeNotifier {
notifyListeners();
try {
// 업데이트 페이로드도 동일한 규칙으로 정규화
final normalized = _sanitizeParticipantPayload(updates);
final data = await _apiService.put(
'${ApiConfig.clubs}/events/$eventId/participants/$participantId',
data: updates,
data: normalized,
);
final updatedParticipant = Participant.fromJson(data['participant']);
@@ -304,6 +320,52 @@ class EventService with ChangeNotifier {
}
}
// 참가자 페이로드 정규화 헬퍼
Map<String, dynamic> _sanitizeParticipantPayload(Map<String, dynamic> data) {
final Map<String, dynamic> out = Map<String, dynamic>.from(data);
// 상태 표준화: 구버전/철자 변형 호환
final statusRaw = (out['status']?.toString().trim() ?? '').toLowerCase();
if (statusRaw.isNotEmpty) {
String status = statusRaw;
if (status == 'cancelled') status = 'canceled';
// 허용 목록: registered, pending, confirmed, canceled
if (![
'registered',
'pending',
'confirmed',
'canceled',
].contains(status)) {
// 허용 외 값은 안전하게 pending 처리
status = 'pending';
}
out['status'] = status;
}
// 결제 상태 표준화: isPaid -> paymentStatus 변환 및 강제
if (out.containsKey('isPaid') &&
(out['paymentStatus'] == null ||
(out['paymentStatus'].toString().isEmpty))) {
final isPaidVal = out['isPaid'] == true;
out['paymentStatus'] = isPaidVal ? 'paid' : 'unpaid';
}
final payRaw = (out['paymentStatus']?.toString().trim() ?? '')
.toLowerCase();
if (payRaw.isNotEmpty) {
out['paymentStatus'] = (payRaw == 'paid') ? 'paid' : 'unpaid';
}
// 서버 스키마에 맞추기 위해 isPaid 키는 제거 (서버는 paymentStatus만 사용)
out.remove('isPaid');
// 빈 문자열을 명시적 null로 변환 (이름/이메일/전화/메모 등)
out.updateAll((key, value) {
if (value is String && value.trim().isEmpty) return null;
return value;
});
return out;
}
// 참가자 삭제
Future<bool> removeParticipant(String eventId, String participantId) async {
if (_token == null || _clubId == null) {
@@ -485,9 +547,7 @@ class EventService with ChangeNotifier {
);
final List<dynamic> teamsData = data['teams'] ?? [];
_teams = teamsData
.map((teamData) => Team.fromJson(teamData))
.toList();
_teams = teamsData.map((teamData) => Team.fromJson(teamData)).toList();
notifyListeners();
return _teams;
@@ -495,7 +555,7 @@ class EventService with ChangeNotifier {
throw Exception('팀 목록을 불러오는데 실패했습니다: $e');
}
}
// 이벤트에 팀이 있는지 확인 (간략 조회)
Future<bool> hasEventTeams(String eventId) async {
if (_token == null) {
@@ -622,7 +682,7 @@ class EventService with ChangeNotifier {
throw Exception('파일에서 이벤트 생성에 실패했습니다: $e');
}
}
// 이벤트 복제
Future<Event> cloneEvent(String eventId, {String? newName}) async {
if (_token == null || _clubId == null) {
@@ -635,7 +695,7 @@ class EventService with ChangeNotifier {
try {
// 원본 이벤트 정보 가져오기
final originalEvent = await fetchEventById(eventId);
// 복제할 이벤트 데이터 준비
final Map<String, dynamic> cloneData = {
'clubId': _clubId,