package handlers import ( "fmt" "html/template" "net/http" "strconv" "go-crm/internal/db" "go-crm/internal/templates" "github.com/go-chi/chi/v5" ) func (a *App) LeadKeywordsPage(w http.ResponseWriter, r *http.Request) { accountID, ok := a.requireAuth(w, r) if !ok { return } clientID := a.clientIDForAccount(accountID) if clientID == 0 { http.Error(w, "No client found for account", http.StatusBadRequest) return } kws, err := db.ListServiceKeywords(a.DB, clientID) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } statuses, _ := db.ListLeadStatuses(a.DB, clientID) services := a.serviceNames(clientID) pendingCount, _ := db.CountLeadsNeedingReview(a.DB, clientID) buf := templates.BufRender() fmt.Fprint(buf, templates.PageHeader("Keyword Mapping", "Auto-detect services from WhatsApp messages")) if pendingCount > 0 { fmt.Fprintf(buf, `
%d pending review
`, pendingCount) } // Service Keywords Section keywordForm := fmt.Sprintf(`
%s`, buildServiceSelectOptions(services), renderKeywordTable(kws)) fmt.Fprint(buf, templates.SectionCard("Service Keywords", "Add keywords that trigger automatic service detection. Case and accent insensitive.", template.HTML(keywordForm))) // Statuses Section statusForm := fmt.Sprintf(`
%s`, renderStatusTable(statuses)) fmt.Fprintf(buf, `
%s
`, templates.SectionCard("Lead Statuses", "Manage the status options available for leads.", template.HTML(statusForm))) w.Header().Set("Content-Type", "text/html; charset=utf-8") templates.WritePage(w, buf, "Keyword Mapping", "") } func (a *App) AddServiceKeyword(w http.ResponseWriter, r *http.Request) { accountID, ok := a.requireAuth(w, r) if !ok { return } clientID := a.clientIDForAccount(accountID) r.ParseForm() svc := r.FormValue("service_name") kw := r.FormValue("keyword") if svc == "" || kw == "" { http.Error(w, "service_name and keyword required", http.StatusBadRequest) return } db.AddServiceKeyword(a.DB, clientID, svc, kw) kws, _ := db.ListServiceKeywords(a.DB, clientID) w.Header().Set("Content-Type", "text/html; charset=utf-8") fmt.Fprint(w, renderKeywordTable(kws)) } func (a *App) DeleteServiceKeywordHandler(w http.ResponseWriter, r *http.Request) { accountID, ok := a.requireAuth(w, r) if !ok { return } clientID := a.clientIDForAccount(accountID) kwID, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64) db.DeleteServiceKeyword(a.DB, clientID, kwID) kws, _ := db.ListServiceKeywords(a.DB, clientID) w.Header().Set("Content-Type", "text/html; charset=utf-8") fmt.Fprint(w, renderKeywordTable(kws)) } func (a *App) AddLeadStatusHandler(w http.ResponseWriter, r *http.Request) { accountID, ok := a.requireAuth(w, r) if !ok { return } clientID := a.clientIDForAccount(accountID) r.ParseForm() statusName := r.FormValue("status_name") if statusName == "" { http.Error(w, "status_name required", http.StatusBadRequest) return } db.AddLeadStatus(a.DB, clientID, statusName) statuses, _ := db.ListLeadStatuses(a.DB, clientID) w.Header().Set("Content-Type", "text/html; charset=utf-8") fmt.Fprint(w, renderStatusTable(statuses)) } func (a *App) DeleteLeadStatusHandler(w http.ResponseWriter, r *http.Request) { accountID, ok := a.requireAuth(w, r) if !ok { return } clientID := a.clientIDForAccount(accountID) statusID, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64) db.DeleteLeadStatus(a.DB, clientID, statusID) statuses, _ := db.ListLeadStatuses(a.DB, clientID) w.Header().Set("Content-Type", "text/html; charset=utf-8") fmt.Fprint(w, renderStatusTable(statuses)) } func buildServiceSelectOptions(services []string) string { out := "" for _, s := range services { if s == "Não especificou" { continue } out += fmt.Sprintf(``, htmlEscape(s), htmlEscape(s)) } return out } func renderKeywordTable(kws []db.ServiceKeyword) string { out := `
` if len(kws) == 0 { out += `` } for _, kw := range kws { out += fmt.Sprintf(` `, htmlEscape(kw.ServiceName), htmlEscape(kw.Keyword), kw.KeywordID) } out += `
ServiceKeywordActions
No keywords defined.
%s %s
` return out } func renderStatusTable(statuses []db.LeadStatus) string { out := `
` if len(statuses) == 0 { out += `` } for _, s := range statuses { out += fmt.Sprintf(` `, htmlEscape(s.StatusName), s.StatusID) } out += `
StatusActions
No statuses defined.
%s
` return out } // --- package-level shims --- func LeadKeywordsPage(w http.ResponseWriter, r *http.Request) { (&App{DB: DB, WAConnector: WAConnector}).LeadKeywordsPage(w, r) } func AddServiceKeyword(w http.ResponseWriter, r *http.Request) { (&App{DB: DB, WAConnector: WAConnector}).AddServiceKeyword(w, r) } func DeleteServiceKeywordHandler(w http.ResponseWriter, r *http.Request) { (&App{DB: DB, WAConnector: WAConnector}).DeleteServiceKeywordHandler(w, r) } func AddLeadStatusHandler(w http.ResponseWriter, r *http.Request) { (&App{DB: DB, WAConnector: WAConnector}).AddLeadStatusHandler(w, r) } func DeleteLeadStatusHandler(w http.ResponseWriter, r *http.Request) { (&App{DB: DB, WAConnector: WAConnector}).DeleteLeadStatusHandler(w, r) }