package website import ( "Portifolio/internal/model" "Portifolio/internal/service" _ "embed" "fmt" "net/http" "strconv" _ "github.com/mattn/go-sqlite3" ) //go:embed static/index.html var indexHTML []byte func Getsite() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Write(indexHTML) } } //go:embed static/styles.css var styleCSS []byte func Getstylesheet() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/css; charset=utf-8") w.Write(styleCSS) } } func HealthFragment(svc *service.Service) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { h := svc.CheckHealth() status := h["status"].(string) uptime := h["uptime"].(string) dotClass := "ok" statusText := "backend ok" if status != "ok" { dotClass = "error" statusText = "backend " + status w.WriteHeader(http.StatusServiceUnavailable) // ← triggers htmx:responseError } dbInfo := h["database"].(map[string]any) dbStatus := dbInfo["status"].(string) dbLatency := dbInfo["latency"].(string) dbText := "db " + dbStatus if dbLatency != "" { dbText += " · " + dbLatency } fmt.Fprintf(w, ` %s · up %s · %s `, dotClass, statusText, uptime, dbText) } } // GET /positions/fragment — returns rows for positions tbody func PositionsFragment(svc *service.Service) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { positions, err := svc.GetPositions() if err != nil { fmt.Fprintf(w, `load failed: %s`, err) return } if len(positions) == 0 { fmt.Fprint(w, `no positions`) return } var total float64 for _, p := range positions { total += p.CostBasis } for _, p := range positions { weight := 0.0 // ← renamed from w to avoid shadowing http.ResponseWriter if total > 0 { weight = p.CostBasis / total * 100 } fmt.Fprintf(w, ` %s %s %s %s
%.1f%%
`, p.Symbol, p.CurrencyCode, fmtInt(p.Shares), fmtNum(p.CostBasis), weight, weight) } } } // GET /positions/fragment — returns rows for positions tbody func CompanyFragment(svc *service.Service) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { companies, err := svc.GetAllCompanies() if err != nil { fmt.Fprintf(w, `load failed: %s`, err) return } if len(companies) == 0 { fmt.Fprint(w, `no positions`) return } for _, c := range companies { fmt.Fprintf(w, ` %s %s %.2f %d %.2f `, c.Symbol, c.CurrencyCode, c.Price, c.SharesOutstanding, c.Price*float64(c.SharesOutstanding)) } } } // GET /positions/fragment — returns rows for positions tbody func SummaryFragment(svc *service.Service) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { positions, err := svc.GetPositions() if err != nil { fmt.Fprintf(w, `load failed: %s`, err) return } if len(positions) == 0 { fmt.Fprint(w, `no positions`) return } var total float64 for _, p := range positions { total += p.CostBasis } for _, p := range positions { weight := 0.0 // ← renamed from w to avoid shadowing http.ResponseWriter if total > 0 { weight = p.CostBasis / total * 100 } fmt.Fprintf(w, ` %s %s %s %s
%.1f%%
`, p.Symbol, p.CurrencyCode, fmtInt(p.Shares), fmtNum(p.CostBasis), weight, weight) } } } func fmtNum(v float64) string { if v == 0 { return "—" } return strconv.FormatFloat(v, 'f', 2, 64) } func fmtInt(v int) string { return strconv.Itoa(v) } var productLabels = map[model.TradeProduct]string{ model.StockTrade: "Stock", model.OptionCallTrade: "Call Option", model.OptionPutTrade: "Put Option", model.CurrencyTrade: "Currency", model.BondTrade: "Bond", } func TradeFragment(svc *service.Service) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { trades, err := svc.GetTrades() if err != nil { fmt.Fprintf(w, `load failed: %s`, err) return } if len(trades) == 0 { fmt.Fprint(w, `no trades`) return } for _, t := range trades { dir, cls := "SELL", "dir-sell" if t.Type == model.BuyType { dir, cls = "BUY", "dir-buy" } label := productLabels[t.Product] fmt.Fprintf(w, ` %s %s %s %s %s %s %s `, t.Symbol, label, t.CurrencyCode, t.Date.Format("2006-01-02"), cls, dir, fmtNum(float64(t.Shares)), fmtNum(t.Price)) } } } func TradeCount(svc *service.Service) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { trades, err := svc.GetTrades() if err != nil { fmt.Fprint(w, "—") return } count := len(trades) if count == 1 { fmt.Fprint(w, "1 trade") } else { fmt.Fprintf(w, "%d trades", count) } } }