Line data Source code
1 : import 'package:flutter/foundation.dart';
2 : import 'package:shared_preferences/shared_preferences.dart';
3 :
4 : import '../config/api_config.dart';
5 : import '../models/score_model.dart';
6 : import './api_service.dart';
7 :
8 : class ScoreService with ChangeNotifier {
9 : List<Score> _scores = [];
10 : bool _isLoading = false;
11 : String? _token;
12 : String? _clubId;
13 : ApiService _apiService = ApiService();
14 : String? _memberId;
15 : String? _eventId;
16 :
17 : // 테스트용 생성자
18 2 : ScoreService.forTest(ApiService apiService, {String? clubId, String? memberId, String? eventId}) {
19 2 : _apiService = apiService;
20 : if (clubId != null) {
21 2 : _clubId = clubId;
22 : }
23 : if (memberId != null) {
24 0 : _memberId = memberId;
25 : }
26 : if (eventId != null) {
27 0 : _eventId = eventId;
28 : }
29 : }
30 :
31 : // 테스트용 getter
32 2 : String? get testMemberId => _memberId;
33 2 : String? get testEventId => _eventId;
34 :
35 : // 기본 생성자
36 0 : ScoreService();
37 :
38 6 : List<Score> get scores => [..._scores];
39 0 : bool get isLoading => _isLoading;
40 :
41 : // 초기화 함수
42 2 : void initialize(String token) {
43 2 : _token = token;
44 4 : _apiService.setToken(token);
45 : }
46 :
47 : // 회원 ID 설정
48 1 : void setMemberId(String memberId) {
49 1 : _memberId = memberId;
50 1 : notifyListeners();
51 : }
52 :
53 : // 이벤트 ID 설정
54 1 : void setEventId(String eventId) {
55 1 : _eventId = eventId;
56 1 : notifyListeners();
57 : }
58 :
59 : // 클럽의 모든 점수 가져오기
60 2 : Future<void> fetchClubScores() async {
61 6 : print('fetchClubScores 호출됨: token=$_token');
62 :
63 2 : _isLoading = true;
64 2 : notifyListeners();
65 :
66 : try {
67 : // 클럽 ID 가져오기
68 2 : final prefs = await SharedPreferences.getInstance();
69 2 : final clubId = prefs.getString(ApiConfig.clubIdKey);
70 :
71 : if (clubId == null) {
72 0 : throw Exception('선택된 클럽이 없습니다');
73 : }
74 :
75 4 : final data = await _apiService.post(
76 : '${ApiConfig.clubs}/scores',
77 2 : data: {'clubId': clubId},
78 : );
79 :
80 : // 응답 데이터가 리스트 형태로 직접 왔는지 확인
81 2 : if (data is List) {
82 : final List<dynamic> scoresData = data;
83 2 : _scores = scoresData
84 6 : .map((scoreData) => Score.fromJson(scoreData))
85 2 : .toList();
86 : } else {
87 : // 응답 데이터가 객체 형태로 왔을 경우 scores 키를 통해 접근
88 1 : final List<dynamic> scoresData = data['scores'] ?? [];
89 1 : _scores = scoresData
90 3 : .map((scoreData) => Score.fromJson(scoreData))
91 1 : .toList();
92 : }
93 :
94 2 : _isLoading = false;
95 2 : notifyListeners();
96 : } catch (e) {
97 1 : _isLoading = false;
98 1 : notifyListeners();
99 2 : throw Exception('점수 목록을 불러오는데 실패했습니다: $e');
100 : }
101 : }
102 :
103 : // 회원의 점수 가져오기
104 2 : Future<List<Score>> fetchMemberScores(String memberId) async {
105 4 : if (_token == null || _clubId == null) {
106 1 : throw Exception('인증 또는 클럽 정보가 필요합니다');
107 : }
108 :
109 2 : _isLoading = true;
110 2 : notifyListeners();
111 :
112 : try {
113 4 : final data = await _apiService.post(
114 : '${ApiConfig.clubs}/members/scores',
115 2 : data: {'memberId': memberId},
116 : );
117 :
118 2 : final List<dynamic> scoresData = data['scores'];
119 :
120 : final memberScores = scoresData
121 6 : .map((scoreData) => Score.fromJson(scoreData))
122 2 : .toList();
123 :
124 2 : _isLoading = false;
125 2 : notifyListeners();
126 :
127 : return memberScores;
128 : } catch (e) {
129 0 : _isLoading = false;
130 0 : notifyListeners();
131 0 : throw Exception('회원 점수를 불러오는데 실패했습니다: $e');
132 : }
133 : }
134 :
135 : // 이벤트의 점수 가져오기
136 2 : Future<List<Score>> fetchEventScores(String eventId) async {
137 4 : if (_token == null || _clubId == null) {
138 0 : throw Exception('인증 또는 클럽 정보가 필요합니다');
139 : }
140 :
141 2 : _isLoading = true;
142 2 : notifyListeners();
143 :
144 : try {
145 4 : final data = await _apiService.post(
146 : '${ApiConfig.clubs}/events/scores',
147 2 : data: {'eventId': eventId},
148 : );
149 :
150 2 : final List<dynamic> scoresData = data['scores'];
151 :
152 : final eventScores = scoresData
153 6 : .map((scoreData) => Score.fromJson(scoreData))
154 2 : .toList();
155 :
156 2 : _isLoading = false;
157 2 : notifyListeners();
158 :
159 : return eventScores;
160 : } catch (e) {
161 0 : _isLoading = false;
162 0 : notifyListeners();
163 0 : throw Exception('이벤트 점수를 불러오는데 실패했습니다: $e');
164 : }
165 : }
166 :
167 : // 점수 추가
168 2 : Future<Score> addScore(Map<String, dynamic> scoreData) async {
169 4 : if (_token == null || _clubId == null) {
170 0 : throw Exception('인증 또는 클럽 정보가 필요합니다');
171 : }
172 :
173 2 : _isLoading = true;
174 2 : notifyListeners();
175 :
176 : try {
177 4 : final data = await _apiService.post(ApiConfig.scores, data: scoreData);
178 :
179 4 : final newScore = Score.fromJson(data['score']);
180 :
181 4 : _scores.add(newScore);
182 :
183 2 : _isLoading = false;
184 2 : notifyListeners();
185 :
186 : return newScore;
187 : } catch (e) {
188 0 : _isLoading = false;
189 0 : notifyListeners();
190 0 : throw Exception('점수 추가에 실패했습니다: $e');
191 : }
192 : }
193 :
194 : // 점수 수정
195 2 : Future<Score> updateScore(
196 : String scoreId,
197 : Map<String, dynamic> updates,
198 : ) async {
199 4 : if (_token == null || _clubId == null) {
200 0 : throw Exception('인증 또는 클럽 정보가 필요합니다');
201 : }
202 :
203 2 : _isLoading = true;
204 2 : notifyListeners();
205 :
206 : try {
207 4 : final data = await _apiService.put(
208 2 : '${ApiConfig.scores}/$scoreId',
209 : data: updates,
210 : );
211 :
212 4 : final updatedScore = Score.fromJson(data['score']);
213 :
214 : // 점수 목록 업데이트
215 10 : final index = _scores.indexWhere((score) => score.id == scoreId);
216 2 : if (index >= 0) {
217 4 : _scores[index] = updatedScore;
218 : }
219 :
220 2 : _isLoading = false;
221 2 : notifyListeners();
222 :
223 : return updatedScore;
224 : } catch (e) {
225 0 : _isLoading = false;
226 0 : notifyListeners();
227 0 : throw Exception('점수 수정에 실패했습니다: $e');
228 : }
229 : }
230 :
231 : // 점수 삭제
232 2 : Future<bool> deleteScore(String scoreId) async {
233 4 : if (_token == null || _clubId == null) {
234 0 : throw Exception('인증 또는 클럽 정보가 필요합니다');
235 : }
236 :
237 2 : _isLoading = true;
238 2 : notifyListeners();
239 :
240 : try {
241 6 : await _apiService.delete('${ApiConfig.scores}/$scoreId');
242 :
243 : // 점수 목록에서 삭제
244 10 : _scores.removeWhere((score) => score.id == scoreId);
245 :
246 2 : _isLoading = false;
247 2 : notifyListeners();
248 :
249 : return true;
250 : } catch (e) {
251 0 : _isLoading = false;
252 0 : notifyListeners();
253 0 : throw Exception('점수 삭제에 실패했습니다: $e');
254 : }
255 : }
256 :
257 : // 회원 통계 가져오기
258 2 : Future<ScoreStatistics> fetchMemberStatistics(String memberId) async {
259 4 : if (_token == null || _clubId == null) {
260 0 : throw Exception('인증 또는 클럽 정보가 필요합니다');
261 : }
262 :
263 : try {
264 4 : final data = await _apiService.post(
265 : '${ApiConfig.clubs}/members/stats',
266 2 : data: {'memberId': memberId},
267 : );
268 :
269 4 : return ScoreStatistics.fromJson(data['statistics']);
270 : } catch (e) {
271 2 : throw Exception('회원 통계를 불러오는데 실패했습니다: $e');
272 : }
273 : }
274 :
275 : // 클럽 통계 가져오기
276 2 : Future<Map<String, ScoreStatistics>> fetchClubStatistics() async {
277 2 : if (_token == null) {
278 0 : throw Exception('인증 정보가 필요합니다');
279 : }
280 :
281 : try {
282 : // 클럽 ID 가져오기
283 2 : final prefs = await SharedPreferences.getInstance();
284 2 : final clubId = prefs.getString(ApiConfig.clubIdKey);
285 :
286 : if (clubId == null) {
287 0 : throw Exception('선택된 클럽이 없습니다');
288 : }
289 :
290 4 : final data = await _apiService.post(
291 : '${ApiConfig.clubs}/scores/stats',
292 2 : data: {'clubId': clubId},
293 : );
294 :
295 2 : final Map<String, ScoreStatistics> statistics = {};
296 :
297 2 : if (data['statistics'] != null) {
298 : final Map<String, dynamic> statsData =
299 2 : data['statistics'] as Map<String, dynamic>;
300 :
301 4 : statsData.forEach((key, value) {
302 : if (value != null) {
303 : try {
304 4 : statistics[key] = ScoreStatistics.fromJson(value);
305 : } catch (e) {
306 0 : print('통계 변환 오류: $key - $e');
307 : }
308 : }
309 : });
310 : }
311 :
312 : return statistics;
313 : } catch (e) {
314 0 : throw Exception('클럽 통계를 불러오는데 실패했습니다: $e');
315 : }
316 : }
317 : }
|