Refactor: Recover middleware now uses RenderError + add full notifications view
- Replaced http.Error with helpers.RenderError in Recover middleware - Custom 500.html now rendered with layout and topbar on panic - RenderError gracefully checks template existence and falls back to plain response - Added /account/notifications full view page (index) - Linked "Back to notifications" from notification read view - Fixed typo in template path for notifications/index.html - Improved layout consistency across error and account pages
This commit is contained in:
@@ -15,7 +15,7 @@ func NotificationsHandler(db *sql.DB) http.HandlerFunc {
|
|||||||
data := BuildTemplateData(db, w, r)
|
data := BuildTemplateData(db, w, r)
|
||||||
context := helpers.TemplateContext(w, r, data)
|
context := helpers.TemplateContext(w, r, data)
|
||||||
|
|
||||||
tmpl := helpers.LoadTemplateFiles("notifications.html", "templates/account/notifications.html")
|
tmpl := helpers.LoadTemplateFiles("index.html", "templates/account/notifications/index.html")
|
||||||
|
|
||||||
err := tmpl.ExecuteTemplate(w, "layout", context)
|
err := tmpl.ExecuteTemplate(w, "layout", context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1,24 +1,40 @@
|
|||||||
package helpers
|
package helpers
|
||||||
|
|
||||||
// ToDo should be a handler?
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"synlotto-website/models"
|
"synlotto-website/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
func RenderError(w http.ResponseWriter, r *http.Request, statusCode int) {
|
func RenderError(w http.ResponseWriter, r *http.Request, statusCode int) {
|
||||||
|
log.Printf("⚙️ RenderError called with status: %d", statusCode)
|
||||||
|
|
||||||
context := TemplateContext(w, r, models.TemplateData{})
|
context := TemplateContext(w, r, models.TemplateData{})
|
||||||
|
|
||||||
page := fmt.Sprintf("templates/error/%d.html", statusCode)
|
pagePath := fmt.Sprintf("templates/error/%d.html", statusCode)
|
||||||
tmpl := LoadTemplateFiles(fmt.Sprintf("%d.html", statusCode), page)
|
log.Printf("📄 Checking for template file: %s", pagePath)
|
||||||
|
|
||||||
|
if _, err := os.Stat(pagePath); err != nil {
|
||||||
|
log.Printf("🚫 Template file missing: %s", err)
|
||||||
|
http.Error(w, http.StatusText(statusCode), statusCode)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("✅ Template file found, loading...")
|
||||||
|
|
||||||
|
tmpl := LoadTemplateFiles(fmt.Sprintf("%d.html", statusCode), pagePath)
|
||||||
|
|
||||||
w.WriteHeader(statusCode)
|
w.WriteHeader(statusCode)
|
||||||
err := tmpl.ExecuteTemplate(w, "layout", context)
|
err := tmpl.ExecuteTemplate(w, "layout", context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("❌ Failed to render error page for %d: %v", statusCode, err)
|
log.Printf("❌ Failed to render error page layout: %v", err)
|
||||||
http.Error(w, http.StatusText(statusCode), statusCode)
|
http.Error(w, http.StatusText(statusCode), statusCode)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Println("✅ Successfully rendered 500 page")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//ToDo Pages.go /template.go to be merged?
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package helpers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"html/template"
|
"html/template"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -69,6 +70,7 @@ func LoadTemplateFiles(name string, files ...string) *template.Template {
|
|||||||
}
|
}
|
||||||
all := append(shared, files...)
|
all := append(shared, files...)
|
||||||
|
|
||||||
|
log.Printf("📄 Loading templates: %v", all)
|
||||||
return template.Must(template.New(name).Funcs(TemplateFuncs()).ParseFiles(all...))
|
return template.Must(template.New(name).Funcs(TemplateFuncs()).ParseFiles(all...))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
1
main.go
1
main.go
@@ -68,6 +68,7 @@ func setupAccountRoutes(mux *http.ServeMux, db *sql.DB) {
|
|||||||
mux.HandleFunc("/signup", middleware.Auth(false)(handlers.Signup))
|
mux.HandleFunc("/signup", middleware.Auth(false)(handlers.Signup))
|
||||||
mux.HandleFunc("/account/tickets/add_ticket", handlers.AddTicket(db))
|
mux.HandleFunc("/account/tickets/add_ticket", handlers.AddTicket(db))
|
||||||
mux.HandleFunc("/account/tickets/my_tickets", handlers.GetMyTickets(db))
|
mux.HandleFunc("/account/tickets/my_tickets", handlers.GetMyTickets(db))
|
||||||
|
mux.HandleFunc("/account/notifications", middleware.Auth(true)(handlers.NotificationsHandler(db)))
|
||||||
mux.HandleFunc("/account/notifications/read", middleware.Auth(true)(handlers.MarkNotificationReadHandler(db)))
|
mux.HandleFunc("/account/notifications/read", middleware.Auth(true)(handlers.MarkNotificationReadHandler(db)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
|
"synlotto-website/helpers"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Recover(next http.Handler) http.Handler {
|
func Recover(next http.Handler) http.Handler {
|
||||||
@@ -12,7 +13,8 @@ func Recover(next http.Handler) http.Handler {
|
|||||||
if rec := recover(); rec != nil {
|
if rec := recover(); rec != nil {
|
||||||
log.Printf("🔥 Recovered from panic: %v\n%s", rec, debug.Stack())
|
log.Printf("🔥 Recovered from panic: %v\n%s", rec, debug.Stack())
|
||||||
|
|
||||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
// ✅ Call your custom template-based fallback
|
||||||
|
helpers.RenderError(w, r, http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
|
|||||||
@@ -1,23 +1,29 @@
|
|||||||
{{ define "notifications" }}
|
{{ define "content" }}
|
||||||
<div class="container py-4">
|
<div class="container py-4">
|
||||||
<h2 class="mb-4">Notifications</h2>
|
<h2 class="mb-4">Your Notifications</h2>
|
||||||
|
|
||||||
{{ if .Notifications }}
|
{{ if .Notifications }}
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
{{ range .Notifications }}
|
{{ range .Notifications }}
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-start {{ if not .IsRead }}fw-bold{{ end }}">
|
<li class="list-group-item d-flex justify-content-between align-items-start {{ if not .IsRead }}bg-light{{ end }}">
|
||||||
<div class="ms-2 me-auto">
|
<div class="ms-2 me-auto">
|
||||||
<div class="fw-semibold">{{ .Title }}</div>
|
<div class="fw-bold">
|
||||||
<small class="text-muted">{{ .Message }}</small>
|
<a href="/account/notifications/read?id={{ .ID }}" class="{{ if not .IsRead }}text-primary fw-bold{{ end }}">
|
||||||
</div>
|
{{ .Subject }}
|
||||||
{{ if not .IsRead }}
|
</a>
|
||||||
<a href="/account/notifications/read?id={{ .ID }}" class="badge bg-primary text-decoration-none">Mark as read</a>
|
</div>
|
||||||
|
<small class="text-muted">{{ .CreatedAt.Format "Jan 2, 2006 15:04" }}</small>
|
||||||
|
</div>
|
||||||
|
{{ if not .IsRead }}
|
||||||
|
<span class="badge bg-warning text-dark">New</span>
|
||||||
|
{{ end }}
|
||||||
|
</li>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</li>
|
</ul>
|
||||||
{{ end }}
|
|
||||||
</ul>
|
|
||||||
{{ else }}
|
{{ else }}
|
||||||
<div class="alert alert-info">You have no notifications.</div>
|
<div class="alert alert-info text-center">
|
||||||
|
You don’t have any notifications.
|
||||||
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|||||||
Reference in New Issue
Block a user