// Package handlers provides HTTP handlers using the generic Store pattern. // This replaces the old CRMHandler with a generic implementation. package handlers import ( "database/sql" "encoding/json" "net/http" "github.com/go-chi/chi/v5" "github.com/lib/pq" "boc/models" "boc/store" ) // CRMHandlerV2 uses the generic Store for customers type CRMHandlerV2 struct { customers *store.Store[*models.Customer] db *store.DB } // NewCRMHandlerV2 creates a new CRM handler using generic store func NewCRMHandlerV2(db *store.DB) *CRMHandlerV2 { cols := []string{"id", "name", "email", "phone", "company", "org_number", "status", "source", "tags", "assigned_to", "created_at", "updated_at"} return &CRMHandlerV2{ customers: store.NewStore(db, "boc_customers", cols, func(rows *sql.Rows) (*models.Customer, error) { c := &models.Customer{} err := c.ScanRow(rows) return c, err }, func(row *sql.Row) (*models.Customer, error) { c := &models.Customer{} err := c.ScanOneRow(row) return c, err }, ), db: db, } } // ListCustomers handles GET /api/v1/crm/customers func (h *CRMHandlerV2) ListCustomers(w http.ResponseWriter, r *http.Request) { status := r.URL.Query().Get("status") if status == "" { status = "active" } customers, err := h.customers.List(r.Context(), "status = $1", status) if err != nil { writeError(w, http.StatusInternalServerError, "database error") return } writeJSON(w, http.StatusOK, map[string]interface{}{ "customers": customers, "total": len(customers), }) } // GetCustomer handles GET /api/v1/crm/customers/{id} func (h *CRMHandlerV2) GetCustomer(w http.ResponseWriter, r *http.Request) { id := chi.URLParam(r, "id") customer, err := h.customers.Get(r.Context(), id) if err != nil { writeError(w, http.StatusNotFound, "customer not found") return } writeJSON(w, http.StatusOK, customer) } // CreateCustomer handles POST /api/v1/crm/customers func (h *CRMHandlerV2) CreateCustomer(w http.ResponseWriter, r *http.Request) { var req models.Customer if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeError(w, http.StatusBadRequest, "invalid request") return } var id string err := h.db.QueryRowContext(r.Context(), ` INSERT INTO boc_customers (name, email, phone, company, org_number, status, source, tags) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING id `, req.Name, req.Email, req.Phone, req.Company, req.OrgNumber, req.Status, req.Source, pq.Array(req.Tags)).Scan(&id) if err != nil { writeError(w, http.StatusInternalServerError, "failed to create customer") return } writeJSON(w, http.StatusCreated, map[string]interface{}{ "id": id, "message": "Customer created", }) } // DeleteCustomer handles DELETE /api/v1/crm/customers/{id} func (h *CRMHandlerV2) DeleteCustomer(w http.ResponseWriter, r *http.Request) { id := chi.URLParam(r, "id") if err := h.customers.Delete(r.Context(), id); err != nil { writeError(w, http.StatusInternalServerError, "failed to delete customer") return } writeJSON(w, http.StatusOK, map[string]interface{}{ "message": "Customer deleted", }) }