diff --git a/internal/repository/analytics_repository.go b/internal/repository/analytics_repository.go index f31b9aa..53f6fab 100644 --- a/internal/repository/analytics_repository.go +++ b/internal/repository/analytics_repository.go @@ -504,6 +504,79 @@ func (r *AnalyticsRepository) GetMonthlyTrend(ctx context.Context, months int) ( return results, nil } +func (r *AnalyticsRepository) GetMonthlyTrendByUserID(ctx context.Context, userID *uuid.UUID, months int) ([]map[string]interface{}, error) { + db := DBFromContext(ctx, r.db) + var results []map[string]interface{} + + // Direct query (since we need to filter by user) + fallbackQuery := ` + WITH monthly_data AS ( + SELECT + TO_CHAR(date_trunc('month', li.created_at), 'Month') as month, + EXTRACT(YEAR FROM li.created_at) as year, + EXTRACT(MONTH FROM li.created_at) as month_num, + COUNT(DISTINCT li.id) as incoming_count, + 0 as outgoing_count + FROM letters_incoming li + INNER JOIN letter_incoming_recipients lir ON lir.letter_id = li.id + WHERE li.deleted_at IS NULL + AND lir.recipient_user_id = ? + AND li.created_at >= NOW() - INTERVAL '%d months' + GROUP BY date_trunc('month', li.created_at), EXTRACT(YEAR FROM li.created_at), EXTRACT(MONTH FROM li.created_at) + + UNION ALL + + SELECT + TO_CHAR(date_trunc('month', lo.created_at), 'Month') as month, + EXTRACT(YEAR FROM lo.created_at) as year, + EXTRACT(MONTH FROM lo.created_at) as month_num, + 0 as incoming_count, + COUNT(DISTINCT lo.id) as outgoing_count + FROM letters_outgoing lo + INNER JOIN letter_outgoing_recipients lor ON lor.letter_id = lo.id + WHERE lo.deleted_at IS NULL + AND lor.user_id = ? + AND lo.created_at >= NOW() - INTERVAL '%d months' + GROUP BY date_trunc('month', lo.created_at), EXTRACT(YEAR FROM lo.created_at), EXTRACT(MONTH FROM lo.created_at) + ) + SELECT + month, + year, + SUM(incoming_count) as incoming_count, + SUM(outgoing_count) as outgoing_count, + SUM(incoming_count + outgoing_count) as total_count, + LAG(SUM(incoming_count + outgoing_count)) OVER (ORDER BY year, month_num) as prev_total + FROM monthly_data + GROUP BY month, year, month_num + ORDER BY year DESC, month_num DESC + LIMIT %d + ` + + fallbackQuery = fmt.Sprintf(fallbackQuery, months, months, months) + + if err := db.Raw(fallbackQuery, userID, userID).Scan(&results).Error; err != nil { + return nil, err + } + + // Calculate growth rate + for i := range results { + if results[i]["prev_total"] != nil { + prevVal, ok := results[i]["prev_total"].(float64) + if ok && prevVal > 0 { + current := getFloat64FromInterface(results[i]["total_count"]) + results[i]["growth_rate"] = ((current - prevVal) / prevVal) * 100 + } else { + results[i]["growth_rate"] = float64(0) + } + } else { + results[i]["growth_rate"] = float64(0) + } + delete(results[i], "prev_total") + } + + return results, nil +} + // Helper function to safely convert interface{} to float64 func getFloat64FromInterface(v interface{}) float64 { if v == nil { @@ -727,17 +800,17 @@ func (r *AnalyticsRepository) GetDailyActivityByUserID(ctx context.Context, user SELECT DATE(created_at) as date, TO_CHAR(created_at, 'Day') as day_of_week, - COUNT(CASE WHEN type = 'incoming' THEN 1 END) as incoming_count, - COUNT(CASE WHEN type = 'outgoing' THEN 1 END) as outgoing_count, + COUNT(DISTINCT CASE WHEN type = 'incoming' THEN letter_id END) as incoming_count, + COUNT(DISTINCT CASE WHEN type = 'outgoing' THEN letter_id END) as outgoing_count, 0 as approved_count, 0 as rejected_count FROM ( - SELECT li.created_at, 'incoming' as type + SELECT li.id as letter_id, li.created_at, 'incoming' as type FROM letters_incoming li INNER JOIN letter_incoming_recipients lir ON lir.letter_id = li.id WHERE li.deleted_at IS NULL AND lir.recipient_user_id = ? UNION ALL - SELECT lo.created_at, 'outgoing' as type + SELECT lo.id as letter_id, lo.created_at, 'outgoing' as type FROM letters_outgoing lo INNER JOIN letter_outgoing_recipients lor ON lor.letter_id = lo.id WHERE lo.deleted_at IS NULL AND lor.user_id = ? diff --git a/internal/service/analytics_service.go b/internal/service/analytics_service.go index 796f73b..28f08d3 100644 --- a/internal/service/analytics_service.go +++ b/internal/service/analytics_service.go @@ -84,7 +84,7 @@ func (s *AnalyticsServiceImpl) GetDashboard(ctx context.Context, req *contract.A response.DepartmentStats = s.mapDepartmentStats(deptData) // Get monthly trend (last 12 months) - monthlyData, err := s.analyticsRepo.GetMonthlyTrend(ctx, 12) + monthlyData, err := s.analyticsRepo.GetMonthlyTrendByUserID(ctx, userID, 12) if err != nil { return nil, err }