package web import ( "bytes" "fmt" "fuj-management/go/internal/web/api" "net/http" "runtime/debug" ) // HTMLHandler serves the Go-native HTML frontend. type HTMLHandler struct { renderer *Renderer build BuildInfo apiHandler *api.Handler actions ActionHandlers } // NewHTMLHandler constructs an HTMLHandler. func NewHTMLHandler(r *Renderer, b BuildInfo, ah *api.Handler, actions ActionHandlers) *HTMLHandler { return &HTMLHandler{renderer: r, build: b, apiHandler: ah, actions: actions} } func (h *HTMLHandler) ServeAdults(w http.ResponseWriter, r *http.Request) { data, err := h.apiHandler.AssembleAdults(r.Context()) if err != nil { h.renderer.Render(w, "adults", AdultsPageData{ PageData: PageData{Active: "adults", Build: h.build}, Error: err.Error(), }) return } h.renderer.Render(w, "adults", AdultsPageData{ PageData: PageData{Active: "adults", Build: h.build}, Data: data, }) } func (h *HTMLHandler) ServeJuniors(w http.ResponseWriter, r *http.Request) { data, err := h.apiHandler.AssembleJuniors(r.Context()) if err != nil { h.renderer.Render(w, "juniors", JuniorsPageData{ PageData: PageData{Active: "juniors", Build: h.build}, Error: err.Error(), }) return } h.renderer.Render(w, "juniors", JuniorsPageData{ PageData: PageData{Active: "juniors", Build: h.build}, Data: data, }) } func (h *HTMLHandler) ServePayments(w http.ResponseWriter, r *http.Request) { data, err := h.apiHandler.AssemblePayments(r.Context()) if err != nil { h.renderer.Render(w, "payments", PaymentsPageData{ PageData: PageData{Active: "payments", Build: h.build}, Error: err.Error(), }) return } h.renderer.Render(w, "payments", PaymentsPageData{ PageData: PageData{Active: "payments", Build: h.build}, Data: data, }) } // ServeSync handles GET /sync-bank: runs sync+infer+flush then renders the result. func (h *HTMLHandler) ServeSync(w http.ResponseWriter, r *http.Request) { pd := PageData{Active: "sync", Build: h.build} if h.actions.BankSync == nil { h.renderer.Render(w, "sync", SyncPageData{ PageData: pd, Output: "Bank sync is not configured.", Success: false, }) return } var buf bytes.Buffer success := true if err := h.actions.BankSync(r.Context(), &buf); err != nil { fmt.Fprintf(&buf, "\nError: %s\n\nStack trace:\n%s", err.Error(), debug.Stack()) success = false } fmt.Fprintln(&buf, "\n=== Flush Cache ===") n, err := h.apiHandler.FlushCache() if err != nil { fmt.Fprintf(&buf, "flush error: %s\n", err.Error()) success = false } else { fmt.Fprintf(&buf, "%d cache file(s) deleted.\n", n) } h.renderer.Render(w, "sync", SyncPageData{ PageData: pd, Output: buf.String(), Success: success, }) } // ServeFlushCacheGET handles GET /flush-cache: renders the confirmation form. func (h *HTMLHandler) ServeFlushCacheGET(w http.ResponseWriter, r *http.Request) { h.renderer.Render(w, "flush_cache", FlushPageData{ PageData: PageData{Active: "flush", Build: h.build}, }) } // ServeFlushCachePOST handles POST /flush-cache: flushes and re-renders with count. func (h *HTMLHandler) ServeFlushCachePOST(w http.ResponseWriter, r *http.Request) { n, _ := h.apiHandler.FlushCache() h.renderer.Render(w, "flush_cache", FlushPageData{ PageData: PageData{Active: "flush", Build: h.build}, Flushed: true, Deleted: n, }) } // ServeQR handles GET /qr: generates and returns a Czech QR Platba PNG. func (h *HTMLHandler) ServeQR(w http.ResponseWriter, r *http.Request) { q := r.URL.Query() account := q.Get("account") amount := q.Get("amount") message := q.Get("message") if account == "" { account = h.apiHandler.Config.QRAccount } if amount == "" { amount = "0" } payload := BuildSPD(account, amount, message, h.apiHandler.Config.QRAccount) png, err := RenderQRCode(payload) if err != nil { http.Error(w, "qr encode: "+err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "image/png") _, _ = w.Write(png) }