Edit Profile
+ + {{else}}Welcome to ReceiptNext
+ {{end}}+ Update your name or department. This appears on all expense reports. +
+ {{else}}Let's set up your profile. This information will appear on your expense reports.
+ {{end}} -diff --git a/internal/handlers/auth.go b/internal/handlers/auth.go index cf5a8f7..85af0bc 100644 --- a/internal/handlers/auth.go +++ b/internal/handlers/auth.go @@ -379,6 +379,72 @@ func (h *AuthHandler) SaveOnboarding(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) } +// --------------------------------------------------------------------------- +// Profile handlers +// --------------------------------------------------------------------------- + +// ProfilePage renders the profile editor with the user's current name and +// department pre-filled. Requires onboarding to be completed first. +func (h *AuthHandler) ProfilePage(w http.ResponseWriter, r *http.Request) { + userID := getUserID(r) + if userID == "" { + w.Header().Set("HX-Redirect", "/") + w.WriteHeader(http.StatusUnauthorized) + return + } + + user, _ := database.GetUserByID(h.DB, userID) + if user == nil || !user.Onboarded { + w.Header().Set("HX-Redirect", "/onboarding") + w.WriteHeader(http.StatusOK) + return + } + + tmpl := getTemplate("onboarding.html") + w.Header().Set("Content-Type", "text/html; charset=utf-8") + if err := tmpl.Execute(w, map[string]string{ + "Name": user.Name, + "Department": user.Department, + "Editing": "true", + }); err != nil { + log.Printf("ERROR [%s] handlers: ProfilePage: execute template: %v", time.Now().Format(time.RFC3339), err) + } +} + +// SaveProfile updates the user's name and department, then redirects to the +// dashboard. Reuses the same DB call as onboarding. +func (h *AuthHandler) SaveProfile(w http.ResponseWriter, r *http.Request) { + userID := getUserID(r) + if userID == "" { + w.Header().Set("HX-Redirect", "/") + w.WriteHeader(http.StatusUnauthorized) + return + } + + if err := r.ParseForm(); err != nil { + renderOnboardingError(w, "Cannot parse form data.") + return + } + + name := strings.TrimSpace(r.FormValue("name")) + department := strings.TrimSpace(r.FormValue("department")) + if name == "" { + renderOnboardingError(w, "Name is required.") + return + } + if department == "" { + department = "-" + } + + if err := database.UpdateUserOnboarding(h.DB, userID, name, department); err != nil { + renderOnboardingError(w, "Failed to save. Please try again.") + return + } + + w.Header().Set("HX-Redirect", "/dashboard") + w.WriteHeader(http.StatusOK) +} + func renderOnboardingError(w http.ResponseWriter, message string) { w.Header().Set("Content-Type", "text/html; charset=utf-8") fmt.Fprintf(w, `
+ Update your name or department. This appears on all expense reports. +
+ {{else}}Let's set up your profile. This information will appear on your expense reports.
+ {{end}} -