update dashboard

This commit is contained in:
efrilm 2025-10-20 20:36:17 +07:00
parent f391b6d853
commit 0c3e1db502
2 changed files with 78 additions and 5 deletions

View File

@ -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 = ?

View File

@ -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
}