// internal/handlers/admin/dashboard.go package handlers // ToDo: move SQL into storage layer import ( "log" "net/http" templateHandlers "synlotto-website/internal/handlers/template" security "synlotto-website/internal/helpers/security" templateHelpers "synlotto-website/internal/helpers/template" "synlotto-website/internal/platform/bootstrap" usersStorage "synlotto-website/internal/storage/users" ) func AdminDashboardHandler(app *bootstrap.App) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { userID, ok := security.GetCurrentUserID(app.SessionManager, r) if !ok { http.Redirect(w, r, "/account/login", http.StatusSeeOther) return } user := usersStorage.GetUserByID(app.DB, userID) if user == nil { http.Error(w, "User not found", http.StatusUnauthorized) return } // Shared template data (loads user, notifications, counts, etc.) data := templateHandlers.BuildTemplateData(app, w, r) context := templateHelpers.TemplateContext(w, r, data) context["User"] = user context["IsAdmin"] = user.IsAdmin // Quick stats (keep here for now; move to storage soon) var ( total, winners int prizeSum float64 ) if err := app.DB.QueryRow(` SELECT COUNT(*), SUM(CASE WHEN is_winner THEN 1 ELSE 0 END), COALESCE(SUM(prize_amount), 0) FROM my_tickets `).Scan(&total, &winners, &prizeSum); err != nil { log.Println("⚠️ Failed to load ticket stats:", err) } context["Stats"] = map[string]interface{}{ "TotalTickets": total, "TotalWinners": winners, "TotalPrizeAmount": prizeSum, } // Recent matcher logs (limit 10) rows, err := app.DB.Query(` SELECT run_at, triggered_by, tickets_matched, winners_found, COALESCE(notes, '') FROM log_ticket_matching ORDER BY run_at DESC LIMIT 10 `) if err != nil { log.Println("⚠️ Failed to load logs:", err) } else { defer rows.Close() var logs []struct { RunAt any TriggeredBy string TicketsMatched int WinnersFound int Notes string } for rows.Next() { var e struct { RunAt any TriggeredBy string TicketsMatched int WinnersFound int Notes string } if err := rows.Scan(&e.RunAt, &e.TriggeredBy, &e.TicketsMatched, &e.WinnersFound, &e.Notes); err != nil { log.Println("⚠️ Failed to scan log row:", err) continue } logs = append(logs, e) } context["MatchLogs"] = logs } tmpl := templateHelpers.LoadTemplateFiles("dashboard.html", "web/templates/admin/dashboard.html") if err := tmpl.ExecuteTemplate(w, "layout", context); err != nil { http.Error(w, "Failed to render dashboard", http.StatusInternalServerError) return } } }