Files
oslstats/internal/handlers/notifications.go

142 lines
3.3 KiB
Go

package handlers
import (
"encoding/json"
"fmt"
"net/http"
"git.haelnorr.com/h/golib/hws"
)
// NotificationType defines the type of notification
type NotificationType string
const (
NotificationSuccess NotificationType = "success"
NotificationWarning NotificationType = "warning"
NotificationInfo NotificationType = "info"
)
// Notification represents a toast notification (success, warning, info)
type Notification struct {
Type NotificationType `json:"type"`
Title string `json:"title"`
Message string `json:"message"`
}
// ErrorModal represents a full-screen error modal (500, 503)
type ErrorModal struct {
Code int `json:"code"`
Title string `json:"title"`
Message string `json:"message"`
Details string `json:"details"`
}
// setHXTrigger sets the HX-Trigger header with JSON-encoded data
func setHXTrigger(w http.ResponseWriter, event string, data any) {
payload := map[string]any{
event: data,
}
jsonData, err := json.Marshal(payload)
if err != nil {
// Fallback if JSON encoding fails
w.Header().Set("HX-Trigger", event)
return
}
w.Header().Set("HX-Trigger", string(jsonData))
}
// formatErrorDetails extracts and formats error details from wrapped errors
func formatErrorDetails(err error) string {
if err == nil {
return ""
}
// Use %+v format to get stack trace from github.com/pkg/errors
return fmt.Sprintf("%+v", err)
}
// notifyToast sends a toast notification via HX-Trigger header
func notifyToast(
w http.ResponseWriter,
notifType NotificationType,
title string,
message string,
) {
notification := Notification{
Type: notifType,
Title: title,
Message: message,
}
setHXTrigger(w, "showNotification", notification)
}
// notifyErrorModal sends a full-screen error modal via HX-Trigger header
func notifyErrorModal(
s *hws.Server,
w http.ResponseWriter,
statusCode int,
title string,
message string,
err error,
) {
modal := ErrorModal{
Code: statusCode,
Title: title,
Message: message,
Details: formatErrorDetails(err),
}
// Log the error
s.LogError(hws.HWSError{
StatusCode: statusCode,
Message: message,
Error: err,
Level: hws.ErrorERROR,
})
// Set response status
w.WriteHeader(statusCode)
// Send notification via HX-Trigger
setHXTrigger(w, "showErrorModal", modal)
}
// notifySuccess sends a success toast notification
func notifySuccess(w http.ResponseWriter, title string, message string) {
notifyToast(w, NotificationSuccess, title, message)
}
// notifyWarning sends a warning toast notification
func notifyWarning(w http.ResponseWriter, title string, message string) {
notifyToast(w, NotificationWarning, title, message)
}
// notifyInfo sends an info toast notification
func notifyInfo(w http.ResponseWriter, title string, message string) {
notifyToast(w, NotificationInfo, title, message)
}
// notifyInternalServiceError sends a 500 error modal
func notifyInternalServiceError(
s *hws.Server,
w http.ResponseWriter,
message string,
err error,
) {
notifyErrorModal(s, w, 500, "Internal Server Error", message, err)
}
// notifyServiceUnavailable sends a 503 error modal
func notifyServiceUnavailable(
s *hws.Server,
w http.ResponseWriter,
message string,
err error,
) {
notifyErrorModal(s, w, 503, "Service Unavailable", message, err)
}