이벤트 가져오기 위젯 테스트 추가 및 테스트 훅 도입
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user