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