mirror of
https://github.com/TracksApp/tracks.git
synced 2025-12-16 15:20:13 +01:00
- Created todos.html template showing user's todos with state badges - Created projects.html template showing project cards in grid layout - Created contexts.html template showing context cards - Added ShowTodos, ShowProjects, ShowContexts handlers to web_handler.go - Added routes for /todos, /projects, /contexts to main.go - All pages show empty state when no data exists - Navigation menu links now work without 404 errors All pages are functional and display user-specific data from the database.
250 lines
6.2 KiB
Go
250 lines
6.2 KiB
Go
package handlers
|
|
|
|
import (
|
|
"html/template"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/TracksApp/tracks/internal/database"
|
|
"github.com/TracksApp/tracks/internal/middleware"
|
|
"github.com/TracksApp/tracks/internal/models"
|
|
"github.com/TracksApp/tracks/internal/services"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// WebHandler handles web UI routes
|
|
type WebHandler struct {
|
|
authService *services.AuthService
|
|
templates *template.Template
|
|
}
|
|
|
|
// NewWebHandler creates a new WebHandler
|
|
func NewWebHandler(authService *services.AuthService, templates *template.Template) *WebHandler {
|
|
return &WebHandler{
|
|
authService: authService,
|
|
templates: templates,
|
|
}
|
|
}
|
|
|
|
// ShowLogin displays the login page
|
|
func (h *WebHandler) ShowLogin(c *gin.Context) {
|
|
// Check if this is first time (no users except admin)
|
|
var count int64
|
|
database.DB.Model(&models.User{}).Count(&count)
|
|
|
|
data := gin.H{
|
|
"Title": "Login",
|
|
"FirstTime": count <= 1,
|
|
}
|
|
|
|
c.Header("Content-Type", "text/html; charset=utf-8")
|
|
// Execute base template with content template
|
|
err := h.templates.Lookup("base.html").Execute(c.Writer, data)
|
|
if err != nil {
|
|
c.String(500, "Template error: "+err.Error())
|
|
return
|
|
}
|
|
}
|
|
|
|
// HandleLogin processes login form submission
|
|
func (h *WebHandler) HandleLogin(c *gin.Context) {
|
|
login := c.PostForm("login")
|
|
password := c.PostForm("password")
|
|
|
|
// Authenticate user
|
|
resp, err := h.authService.Login(services.LoginRequest{
|
|
Login: login,
|
|
Password: password,
|
|
})
|
|
|
|
if err != nil {
|
|
var count int64
|
|
database.DB.Model(&models.User{}).Count(&count)
|
|
|
|
data := gin.H{
|
|
"Title": "Login",
|
|
"Error": "Invalid username or password",
|
|
"FirstTime": count <= 1,
|
|
}
|
|
c.Header("Content-Type", "text/html; charset=utf-8")
|
|
h.templates.ExecuteTemplate(c.Writer, "base.html", data)
|
|
return
|
|
}
|
|
|
|
// Set session cookie
|
|
c.SetCookie("tracks_token", resp.Token, 60*60*24*7, "/", "", false, true)
|
|
|
|
// Redirect to dashboard
|
|
c.Redirect(http.StatusFound, "/")
|
|
}
|
|
|
|
// HandleLogout logs out the user
|
|
func (h *WebHandler) HandleLogout(c *gin.Context) {
|
|
// Clear session cookie
|
|
c.SetCookie("tracks_token", "", -1, "/", "", false, true)
|
|
c.Redirect(http.StatusFound, "/login")
|
|
}
|
|
|
|
// ShowDashboard displays the dashboard
|
|
func (h *WebHandler) ShowDashboard(c *gin.Context) {
|
|
user, _ := middleware.GetCurrentUser(c)
|
|
|
|
// Get statistics
|
|
var stats struct {
|
|
ActiveTodos int64
|
|
ActiveProjects int64
|
|
ActiveContexts int64
|
|
CompletedToday int64
|
|
}
|
|
|
|
database.DB.Model(&models.Todo{}).Where("user_id = ? AND state = ?", user.ID, "active").Count(&stats.ActiveTodos)
|
|
database.DB.Model(&models.Project{}).Where("user_id = ? AND state = ?", user.ID, "active").Count(&stats.ActiveProjects)
|
|
database.DB.Model(&models.Context{}).Where("user_id = ? AND state = ?", user.ID, "active").Count(&stats.ActiveContexts)
|
|
|
|
today := time.Now().Truncate(24 * time.Hour)
|
|
database.DB.Model(&models.Todo{}).
|
|
Where("user_id = ? AND state = ? AND completed_at >= ?", user.ID, "completed", today).
|
|
Count(&stats.CompletedToday)
|
|
|
|
// Get recent todos
|
|
var recentTodos []models.Todo
|
|
database.DB.
|
|
Preload("Context").
|
|
Preload("Project").
|
|
Where("user_id = ?", user.ID).
|
|
Order("created_at DESC").
|
|
Limit(10).
|
|
Find(&recentTodos)
|
|
|
|
data := gin.H{
|
|
"Title": "Dashboard",
|
|
"User": user,
|
|
"Stats": stats,
|
|
"RecentTodos": recentTodos,
|
|
}
|
|
|
|
c.Header("Content-Type", "text/html; charset=utf-8")
|
|
h.templates.ExecuteTemplate(c.Writer, "base.html", data)
|
|
}
|
|
|
|
// ShowAdminUsers displays the user management page
|
|
func (h *WebHandler) ShowAdminUsers(c *gin.Context) {
|
|
user, _ := middleware.GetCurrentUser(c)
|
|
|
|
// Get all users
|
|
var users []models.User
|
|
database.DB.Order("id ASC").Find(&users)
|
|
|
|
data := gin.H{
|
|
"Title": "User Management",
|
|
"User": user,
|
|
"Users": users,
|
|
}
|
|
|
|
c.Header("Content-Type", "text/html; charset=utf-8")
|
|
h.templates.ExecuteTemplate(c.Writer, "base.html", data)
|
|
}
|
|
|
|
// HandleCreateUser processes user creation form
|
|
func (h *WebHandler) HandleCreateUser(c *gin.Context) {
|
|
user, _ := middleware.GetCurrentUser(c)
|
|
|
|
login := c.PostForm("login")
|
|
password := c.PostForm("password")
|
|
firstName := c.PostForm("first_name")
|
|
lastName := c.PostForm("last_name")
|
|
isAdmin := c.PostForm("is_admin") == "true"
|
|
|
|
// Create user
|
|
_, err := h.authService.CreateUser(services.CreateUserRequest{
|
|
Login: login,
|
|
Password: password,
|
|
FirstName: firstName,
|
|
LastName: lastName,
|
|
IsAdmin: isAdmin,
|
|
})
|
|
|
|
if err != nil {
|
|
// Get all users for re-rendering
|
|
var users []models.User
|
|
database.DB.Order("id ASC").Find(&users)
|
|
|
|
data := gin.H{
|
|
"Title": "User Management",
|
|
"User": user,
|
|
"Users": users,
|
|
"Error": err.Error(),
|
|
}
|
|
c.Header("Content-Type", "text/html; charset=utf-8")
|
|
h.templates.ExecuteTemplate(c.Writer, "base.html", data)
|
|
return
|
|
}
|
|
|
|
// Redirect back to users page with success message
|
|
c.Redirect(http.StatusFound, "/admin/users?success=User created successfully")
|
|
}
|
|
|
|
// ShowTodos displays the todos page
|
|
func (h *WebHandler) ShowTodos(c *gin.Context) {
|
|
user, _ := middleware.GetCurrentUser(c)
|
|
|
|
// Get user's todos
|
|
var todos []models.Todo
|
|
database.DB.
|
|
Preload("Context").
|
|
Preload("Project").
|
|
Where("user_id = ?", user.ID).
|
|
Order("created_at DESC").
|
|
Find(&todos)
|
|
|
|
data := gin.H{
|
|
"Title": "Todos",
|
|
"User": user,
|
|
"Todos": todos,
|
|
}
|
|
|
|
c.Header("Content-Type", "text/html; charset=utf-8")
|
|
h.templates.ExecuteTemplate(c.Writer, "base.html", data)
|
|
}
|
|
|
|
// ShowProjects displays the projects page
|
|
func (h *WebHandler) ShowProjects(c *gin.Context) {
|
|
user, _ := middleware.GetCurrentUser(c)
|
|
|
|
// Get user's projects
|
|
var projects []models.Project
|
|
database.DB.
|
|
Where("user_id = ?", user.ID).
|
|
Order("created_at DESC").
|
|
Find(&projects)
|
|
|
|
data := gin.H{
|
|
"Title": "Projects",
|
|
"User": user,
|
|
"Projects": projects,
|
|
}
|
|
|
|
c.Header("Content-Type", "text/html; charset=utf-8")
|
|
h.templates.ExecuteTemplate(c.Writer, "base.html", data)
|
|
}
|
|
|
|
// ShowContexts displays the contexts page
|
|
func (h *WebHandler) ShowContexts(c *gin.Context) {
|
|
user, _ := middleware.GetCurrentUser(c)
|
|
|
|
// Get user's contexts
|
|
var contexts []models.Context
|
|
database.DB.
|
|
Where("user_id = ?", user.ID).
|
|
Order("position ASC").
|
|
Find(&contexts)
|
|
|
|
data := gin.H{
|
|
"Title": "Contexts",
|
|
"User": user,
|
|
"Contexts": contexts,
|
|
}
|
|
|
|
c.Header("Content-Type", "text/html; charset=utf-8")
|
|
h.templates.ExecuteTemplate(c.Writer, "base.html", data)
|
|
}
|