From 637507f02af866c5c2968f8d934db11ea843ce0a Mon Sep 17 00:00:00 2001 From: JiWoong Sul Date: Wed, 3 Dec 2025 18:31:37 +0900 Subject: [PATCH] =?UTF-8?q?fix(calendar):=20=EC=9B=94=EB=B3=84=20=EB=B0=A9?= =?UTF-8?q?=EB=AC=B8=20=EC=B9=B4=ED=85=8C=EA=B3=A0=EB=A6=AC=20=EC=A7=91?= =?UTF-8?q?=EA=B3=84=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../calendar/widgets/visit_statistics.dart | 40 ++++++++++++++++--- .../providers/visit_provider.dart | 28 +++++++++++++ 2 files changed, 62 insertions(+), 6 deletions(-) diff --git a/lib/presentation/pages/calendar/widgets/visit_statistics.dart b/lib/presentation/pages/calendar/widgets/visit_statistics.dart index cf0cf25..622ca58 100644 --- a/lib/presentation/pages/calendar/widgets/visit_statistics.dart +++ b/lib/presentation/pages/calendar/widgets/visit_statistics.dart @@ -22,6 +22,12 @@ class VisitStatistics extends ConsumerWidget { month: selectedMonth.month, )), ); + final monthlyCategoryStatsAsync = ref.watch( + monthlyCategoryVisitStatsProvider(( + year: selectedMonth.year, + month: selectedMonth.month, + )), + ); // 자주 방문한 맛집 final frequentRestaurantsAsync = ref.watch(frequentRestaurantsProvider); @@ -34,7 +40,11 @@ class VisitStatistics extends ConsumerWidget { child: Column( children: [ // 이번 달 통계 - _buildMonthlyStats(monthlyStatsAsync, isDark), + _buildMonthlyStats( + monthlyStatsAsync, + monthlyCategoryStatsAsync, + isDark, + ), const SizedBox(height: 16), const NativeAdPlaceholder(height: 360), @@ -53,6 +63,7 @@ class VisitStatistics extends ConsumerWidget { Widget _buildMonthlyStats( AsyncValue> statsAsync, + AsyncValue> categoryStatsAsync, bool isDark, ) { return Card( @@ -75,9 +86,17 @@ class VisitStatistics extends ConsumerWidget { 0, (sum, count) => sum + count, ); - final categoryCounts = - stats.entries.where((e) => !e.key.contains('/')).toList() + final categoryCounts = categoryStatsAsync.maybeWhen( + data: (data) { + final entries = data.entries.toList() ..sort((a, b) => b.value.compareTo(a.value)); + return entries; + }, + orElse: () => >[], + ); + final topCategory = categoryCounts.isNotEmpty + ? categoryCounts.first + : null; return Column( children: [ @@ -89,12 +108,21 @@ class VisitStatistics extends ConsumerWidget { isDark: isDark, ), const SizedBox(height: 12), - if (categoryCounts.isNotEmpty) ...[ + if (topCategory != null) ...[ _buildStatItem( icon: Icons.favorite, label: '가장 많이 간 카테고리', - value: - '${categoryCounts.first.key} (${categoryCounts.first.value}회)', + value: '${topCategory.key} (${topCategory.value}회)', + color: AppColors.lightSecondary, + isDark: isDark, + ), + ] else ...[ + _buildStatItem( + icon: Icons.favorite_border, + label: '가장 많이 간 카테고리', + value: categoryStatsAsync.isLoading + ? '집계 중...' + : '데이터 없음', color: AppColors.lightSecondary, isDark: isDark, ), diff --git a/lib/presentation/providers/visit_provider.dart b/lib/presentation/providers/visit_provider.dart index ddd677c..46624b9 100644 --- a/lib/presentation/providers/visit_provider.dart +++ b/lib/presentation/providers/visit_provider.dart @@ -35,6 +35,34 @@ final monthlyVisitStatsProvider = return repository.getMonthlyVisitStats(params.year, params.month); }); +/// 월별 카테고리별 방문 통계 Provider +final monthlyCategoryVisitStatsProvider = + FutureProvider.family, ({int year, int month})>(( + ref, + params, + ) async { + final repository = ref.watch(visitRepositoryProvider); + final restaurants = await ref.watch(restaurantListProvider.future); + + final records = await repository.getVisitRecordsByDateRange( + startDate: DateTime(params.year, params.month, 1), + endDate: DateTime(params.year, params.month + 1, 0), + ); + + final categoryCount = {}; + for (final record in records) { + final restaurant = restaurants + .where((r) => r.id == record.restaurantId) + .firstOrNull; + if (restaurant == null) continue; + + categoryCount[restaurant.category] = + (categoryCount[restaurant.category] ?? 0) + 1; + } + + return categoryCount; + }); + /// 방문 기록 관리 StateNotifier class VisitNotifier extends StateNotifier> { final VisitRepository _repository;