fix(calendar): 월별 방문 카테고리 집계 반영

This commit is contained in:
JiWoong Sul
2025-12-03 18:31:37 +09:00
parent 3f659432e9
commit 637507f02a
2 changed files with 62 additions and 6 deletions

View File

@@ -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<Map<String, int>> statsAsync,
AsyncValue<Map<String, int>> 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: () => <MapEntry<String, int>>[],
);
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,
),

View File

@@ -35,6 +35,34 @@ final monthlyVisitStatsProvider =
return repository.getMonthlyVisitStats(params.year, params.month);
});
/// 월별 카테고리별 방문 통계 Provider
final monthlyCategoryVisitStatsProvider =
FutureProvider.family<Map<String, int>, ({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 = <String, int>{};
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<AsyncValue<void>> {
final VisitRepository _repository;