package main import ( "html/template" "net/http" ) func (a *App) renderTemplate(w http.ResponseWriter, path string, data any) { tmpl, err := template.ParseFiles(path) if err != nil { http.Error(w, "template parse failed", http.StatusInternalServerError) return } w.Header().Set("Content-Type", "text/html; charset=utf-8") if err := tmpl.Execute(w, data); err != nil { http.Error(w, "template render failed", http.StatusInternalServerError) } } func (a *App) handleDashboard(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { http.Error(w, "method not allowed", http.StatusMethodNotAllowed) return } settings, err := a.getSettings() if err != nil { http.Error(w, "settings read failed", http.StatusInternalServerError) return } plans, err := a.listPlans() if err != nil { http.Error(w, "plans read failed", http.StatusInternalServerError) return } crops, err := a.listCrops() if err != nil { http.Error(w, "crops read failed", http.StatusInternalServerError) return } products, err := a.listProducts() if err != nil { http.Error(w, "products read failed", http.StatusInternalServerError) return } stepMap, err := a.listCropStepsMap() if err != nil { http.Error(w, "steps read failed", http.StatusInternalServerError) return } customTasks, err := a.listCustomTasks() if err != nil { http.Error(w, "custom tasks read failed", http.StatusInternalServerError) return } doneMap, err := a.listTaskCompletionsMap() if err != nil { http.Error(w, "completions read failed", http.StatusInternalServerError) return } data := DashboardPage{ BasePage: BasePage{ ActivePath: "/", Error: r.URL.Query().Get("error"), Info: r.URL.Query().Get("info"), }, Settings: settings, CurrentMonth: monthNames[settings.CurrentMonth-1], TodayTasks: buildTasksForDay(plans, crops, products, stepMap, customTasks, doneMap, (settings.CurrentCycle*12)+(settings.CurrentMonth-1), settings.CurrentDay), Calendar: buildCalendar(plans, crops, products, stepMap, customTasks, doneMap, (settings.CurrentCycle*12)+(settings.CurrentMonth-1), settings.CurrentDay, settings.DaysPerMonth, 14), PlanningCount: len(plans), } if a.matrix != nil { data.MatrixEnabled = true data.MatrixRoomID = a.matrix.RoomID msgs, err := a.matrix.FetchRecentMessages(r.Context()) if err != nil { data.MatrixError = err.Error() } else { data.MatrixMessages = msgs } } data.TodayGroups = groupTasksByField(data.TodayTasks) a.renderTemplate(w, "templates/dashboard.html", data) } func (a *App) handleFieldsPage(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { http.Error(w, "method not allowed", http.StatusMethodNotAllowed) return } fields, err := a.listFields() if err != nil { http.Error(w, "fields read failed", http.StatusInternalServerError) return } data := FieldsPage{ BasePage: BasePage{ ActivePath: "/fields", Error: r.URL.Query().Get("error"), Info: r.URL.Query().Get("info"), }, Fields: fields, Groups: buildFieldGroups(fields), } a.renderTemplate(w, "templates/fields.html", data) } func (a *App) handleCropsPage(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { http.Error(w, "method not allowed", http.StatusMethodNotAllowed) return } crops, err := a.listCrops() if err != nil { http.Error(w, "crops read failed", http.StatusInternalServerError) return } steps, err := a.listCropSteps() if err != nil { http.Error(w, "steps read failed", http.StatusInternalServerError) return } products, err := a.listProducts() if err != nil { http.Error(w, "products read failed", http.StatusInternalServerError) return } data := CropsPage{ BasePage: BasePage{ ActivePath: "/crops", Error: r.URL.Query().Get("error"), Info: r.URL.Query().Get("info"), }, Crops: crops, CropSteps: steps, Products: products, } a.renderTemplate(w, "templates/crops.html", data) } func (a *App) handlePlanningPage(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { http.Error(w, "method not allowed", http.StatusMethodNotAllowed) return } settings, err := a.getSettings() if err != nil { http.Error(w, "settings read failed", http.StatusInternalServerError) return } crops, err := a.listCrops() if err != nil { http.Error(w, "crops read failed", http.StatusInternalServerError) return } fields, err := a.listFields() if err != nil { http.Error(w, "fields read failed", http.StatusInternalServerError) return } plans, err := a.listPlans() if err != nil { http.Error(w, "plans read failed", http.StatusInternalServerError) return } taskTemplates, err := a.listCustomTaskTemplates() if err != nil { http.Error(w, "templates read failed", http.StatusInternalServerError) return } customTasks, err := a.listCustomTasks() if err != nil { http.Error(w, "custom tasks read failed", http.StatusInternalServerError) return } data := PlanningPage{ BasePage: BasePage{ ActivePath: "/planning", Error: r.URL.Query().Get("error"), Info: r.URL.Query().Get("info"), }, Settings: settings, Months: monthOptions(), CycleOffsets: cycleOffsetOptions(8), Crops: crops, Plans: plans, PlanningTargets: buildPlanningTargets(fields), TaskTemplates: taskTemplates, CustomTasks: customTasks, } a.renderTemplate(w, "templates/planning.html", data) } func (a *App) handleGeneralPage(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { http.Error(w, "method not allowed", http.StatusMethodNotAllowed) return } settings, err := a.getSettings() if err != nil { http.Error(w, "settings read failed", http.StatusInternalServerError) return } data := GeneralPage{ BasePage: BasePage{ ActivePath: "/general", Error: r.URL.Query().Get("error"), Info: r.URL.Query().Get("info"), }, Settings: settings, Months: monthOptions(), } a.renderTemplate(w, "templates/general.html", data) }