package handlers import ( "html/template" "mealprep/auth" "mealprep/database" "net/http" "strconv" "strings" ) // MealsHandler handles the meals page func MealsHandler(w http.ResponseWriter, r *http.Request) { userID := auth.GetUserID(r) meals, err := database.GetAllMeals(userID) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } tmpl := `

Meals

{{range .}}
{{if .ImageURL}} {{.Name}} {{end}}
{{.Name}} {{.MealType}} {{if gt .PrepTime 0}} ⏱️ {{.PrepTime}} min {{end}}
{{.Description}} {{if .Instructions}}
Instructions

{{.Instructions}}

{{end}}
{{end}}
` t := template.Must(template.New("meals").Parse(tmpl)) t.Execute(w, meals) } // AddMealHandler handles adding a new meal func AddMealHandler(w http.ResponseWriter, r *http.Request) { userID := auth.GetUserID(r) if err := r.ParseForm(); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } name := strings.TrimSpace(r.FormValue("name")) description := strings.TrimSpace(r.FormValue("description")) mealType := r.FormValue("meal_type") instructions := strings.TrimSpace(r.FormValue("instructions")) imageURL := strings.TrimSpace(r.FormValue("image_url")) prepTime := 0 if prepTimeStr := r.FormValue("prep_time"); prepTimeStr != "" { prepTime, _ = strconv.Atoi(prepTimeStr) } if name == "" || mealType == "" { http.Error(w, "Name and meal type are required", http.StatusBadRequest) return } // Validate meal type if mealType != "breakfast" && mealType != "lunch" && mealType != "snack" { http.Error(w, "Invalid meal type", http.StatusBadRequest) return } id, err := database.AddMeal(userID, name, description, mealType, instructions, imageURL, prepTime) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } tmpl := `
{{if .ImageURL}} {{.Name}} {{end}}
{{.Name}} {{.MealType}} {{if gt .PrepTime 0}} ⏱️ {{.PrepTime}} min {{end}}
{{.Description}} {{if .Instructions}}
Instructions

{{.Instructions}}

{{end}}
` data := struct { ID int64 Name string Description string MealType string Instructions string PrepTime int ImageURL string }{id, name, description, mealType, instructions, prepTime, imageURL} t := template.Must(template.New("meal").Parse(tmpl)) t.Execute(w, data) } // DeleteMealHandler handles deleting a meal func DeleteMealHandler(w http.ResponseWriter, r *http.Request) { userID := auth.GetUserID(r) idStr := strings.TrimPrefix(r.URL.Path, "/meals/") id, err := strconv.Atoi(idStr) if err != nil { http.Error(w, "Invalid ID", http.StatusBadRequest) return } if err := database.DeleteMeal(userID, id); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) } // GetMealIngredientsHandler shows ingredients for a specific meal func GetMealIngredientsHandler(w http.ResponseWriter, r *http.Request) { userID := auth.GetUserID(r) parts := strings.Split(r.URL.Path, "/") if len(parts) < 3 { http.Error(w, "Invalid URL", http.StatusBadRequest) return } mealID, err := strconv.Atoi(parts[2]) if err != nil { http.Error(w, "Invalid meal ID", http.StatusBadRequest) return } mealIngredients, err := database.GetMealIngredients(userID, mealID) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } allIngredients, err := database.GetAllIngredients(userID) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } tmpl := `

Ingredients:

{{range .MealIngredients}}
{{.IngredientName}}: {{.Quantity}} {{.Unit}}
{{end}}
` data := struct { MealID int MealIngredients interface{} AllIngredients interface{} }{ MealID: mealID, MealIngredients: mealIngredients, AllIngredients: allIngredients, } t := template.Must(template.New("mealIngredients").Parse(tmpl)) t.Execute(w, data) } // AddMealIngredientHandler adds an ingredient to a meal func AddMealIngredientHandler(w http.ResponseWriter, r *http.Request) { userID := auth.GetUserID(r) parts := strings.Split(r.URL.Path, "/") if len(parts) < 3 { http.Error(w, "Invalid URL", http.StatusBadRequest) return } mealID, err := strconv.Atoi(parts[2]) if err != nil { http.Error(w, "Invalid meal ID", http.StatusBadRequest) return } if err := r.ParseForm(); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } ingredientID, err := strconv.Atoi(r.FormValue("ingredient_id")) if err != nil { http.Error(w, "Invalid ingredient ID", http.StatusBadRequest) return } quantity, err := strconv.ParseFloat(r.FormValue("quantity"), 64) if err != nil { http.Error(w, "Invalid quantity", http.StatusBadRequest) return } if err := database.AddMealIngredient(userID, mealID, ingredientID, quantity); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // Get the ingredient details to display ingredients, err := database.GetMealIngredients(userID, mealID) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // Find the ingredient we just added var addedIngredient *interface{} for _, ing := range ingredients { if ing.IngredientID == ingredientID { var temp interface{} = ing addedIngredient = &temp break } } if addedIngredient == nil { http.Error(w, "Could not find added ingredient", http.StatusInternalServerError) return } tmpl := `
{{.IngredientName}}: {{.Quantity}} {{.Unit}}
` t := template.Must(template.New("mealIngredient").Parse(tmpl)) t.Execute(w, *addedIngredient) } // DeleteMealIngredientHandler removes an ingredient from a meal func DeleteMealIngredientHandler(w http.ResponseWriter, r *http.Request) { userID := auth.GetUserID(r) parts := strings.Split(r.URL.Path, "/") if len(parts) < 5 { http.Error(w, "Invalid URL", http.StatusBadRequest) return } mealID, err := strconv.Atoi(parts[2]) if err != nil { http.Error(w, "Invalid meal ID", http.StatusBadRequest) return } ingredientID, err := strconv.Atoi(parts[4]) if err != nil { http.Error(w, "Invalid ingredient ID", http.StatusBadRequest) return } if err := database.DeleteMealIngredient(userID, mealID, ingredientID); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) } // GetEditMealHandler shows the edit modal for a meal func GetEditMealHandler(w http.ResponseWriter, r *http.Request) { userID := auth.GetUserID(r) parts := strings.Split(r.URL.Path, "/") if len(parts) < 3 { http.Error(w, "Invalid URL", http.StatusBadRequest) return } mealID, err := strconv.Atoi(parts[2]) if err != nil { http.Error(w, "Invalid meal ID", http.StatusBadRequest) return } // Get meal with security check meal, err := database.GetMealByID(userID, mealID) if err != nil { http.Error(w, "Meal not found", http.StatusNotFound) return } tmpl := ` ` t := template.Must(template.New("editMeal").Parse(tmpl)) t.Execute(w, meal) } // UpdateMealHandler updates a meal func UpdateMealHandler(w http.ResponseWriter, r *http.Request) { userID := auth.GetUserID(r) parts := strings.Split(r.URL.Path, "/") if len(parts) < 3 { http.Error(w, "Invalid URL", http.StatusBadRequest) return } mealID, err := strconv.Atoi(parts[2]) if err != nil { http.Error(w, "Invalid meal ID", http.StatusBadRequest) return } // Verify ownership _, err = database.GetMealByID(userID, mealID) if err != nil { http.Error(w, "Meal not found or access denied", http.StatusForbidden) return } if err := r.ParseForm(); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } name := strings.TrimSpace(r.FormValue("name")) description := strings.TrimSpace(r.FormValue("description")) mealType := r.FormValue("meal_type") instructions := strings.TrimSpace(r.FormValue("instructions")) imageURL := strings.TrimSpace(r.FormValue("image_url")) prepTime := 0 if prepTimeStr := r.FormValue("prep_time"); prepTimeStr != "" { prepTime, _ = strconv.Atoi(prepTimeStr) } if name == "" || mealType == "" { http.Error(w, "Name and meal type are required", http.StatusBadRequest) return } // Validate meal type if mealType != "breakfast" && mealType != "lunch" && mealType != "snack" { http.Error(w, "Invalid meal type", http.StatusBadRequest) return } // Update meal _, err = database.DB.Exec( "UPDATE meals SET name = ?, description = ?, meal_type = ?, instructions = ?, prep_time = ?, image_url = ? WHERE id = ? AND user_id = ?", name, description, mealType, instructions, prepTime, imageURL, mealID, userID, ) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // Return updated meal card tmpl := `
{{if .ImageURL}} {{.Name}} {{end}}
{{.Name}} {{.MealType}} {{if gt .PrepTime 0}} ⏱️ {{.PrepTime}} min {{end}}
{{.Description}} {{if .Instructions}}
Instructions

{{.Instructions}}

{{end}}
` data := struct { ID int Name string Description string MealType string Instructions string PrepTime int ImageURL string }{mealID, name, description, mealType, instructions, prepTime, imageURL} t := template.Must(template.New("updatedMeal").Parse(tmpl)) t.Execute(w, data) }