@danhachuel/leadmaster 0.1.24 → 0.1.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/backend/__pycache__/main.cpython-311.pyc +0 -0
  3. package/backend/main.py +18 -0
  4. package/backend/services/__pycache__/__init__.cpython-311.pyc +0 -0
  5. package/backend/services/__pycache__/agents.cpython-311.pyc +0 -0
  6. package/backend/services/__pycache__/crm_agent.cpython-311.pyc +0 -0
  7. package/backend/services/__pycache__/extractors.cpython-311.pyc +0 -0
  8. package/backend/services/__pycache__/flags.cpython-311.pyc +0 -0
  9. package/backend/services/__pycache__/llm.cpython-311.pyc +0 -0
  10. package/backend/services/__pycache__/storage.cpython-311.pyc +0 -0
  11. package/backend/tests/__pycache__/conftest.cpython-311-pytest-8.4.2.pyc +0 -0
  12. package/backend/tests/__pycache__/test_agents_routes.cpython-311-pytest-8.4.2.pyc +0 -0
  13. package/backend/tests/__pycache__/test_campaigns_routes.cpython-311-pytest-8.4.2.pyc +0 -0
  14. package/backend/tests/__pycache__/test_cnpj_extractor.cpython-311-pytest-8.4.2.pyc +0 -0
  15. package/backend/tests/__pycache__/test_config.cpython-311-pytest-8.4.2.pyc +0 -0
  16. package/backend/tests/__pycache__/test_crm_routes.cpython-311-pytest-8.4.2.pyc +0 -0
  17. package/backend/tests/__pycache__/test_extractors_real.cpython-311-pytest-8.4.2.pyc +0 -0
  18. package/backend/tests/__pycache__/test_funnel_routes.cpython-311-pytest-8.4.2.pyc +0 -0
  19. package/backend/tests/__pycache__/test_instagram_extractor.cpython-311-pytest-8.4.2.pyc +0 -0
  20. package/backend/tests/__pycache__/test_launcher_protections.cpython-311-pytest-8.4.2.pyc +0 -0
  21. package/backend/tests/__pycache__/test_lead_edit_routes.cpython-311-pytest-8.4.2.pyc +0 -0
  22. package/backend/tests/__pycache__/test_maps_extractor.cpython-311-pytest-8.4.2.pyc +0 -0
  23. package/backend/tests/__pycache__/test_metrics.cpython-311-pytest-8.4.2.pyc +0 -0
  24. package/backend/tests/__pycache__/test_process_flags.cpython-311-pytest-8.4.2.pyc +0 -0
  25. package/backend/tests/__pycache__/test_webhook_routes.cpython-311-pytest-8.4.2.pyc +0 -0
  26. package/backend/tests/test_lead_edit_routes.py +63 -0
  27. package/frontend/dist/assets/{index-ViDiQGJH.css → index-BLuj5jS4.css} +1 -1
  28. package/frontend/dist/assets/index-C1mEC85V.js +90 -0
  29. package/frontend/dist/index.html +2 -2
  30. package/package.json +1 -1
  31. package/frontend/dist/assets/index-B_SzrvJP.js +0 -90
package/CHANGELOG.md CHANGED
@@ -37,6 +37,28 @@ normaliza para a forma canônica (ex.: `0.1.0`).
37
37
  falha se `process.stdin.resume();` desaparecer, se `.unref()` aparecer, se o
38
38
  ciclo de vida vinculado for removido ou se os handlers globais sumirem.
39
39
 
40
+ ## [0.1.25] — 2026-11-09
41
+
42
+ ### Adicionado
43
+
44
+ - **Modal de Detalhes do Lead no CRM (clique no card):**
45
+ - Rota `PUT /api/crm/leads/{lead_id}` — edição de `nome`, `telefone` e `email`
46
+ (todos opcionais no payload); nome vazio → **400** (prevenção de erros),
47
+ lead inexistente → **404**, payload sem campos editáveis → **400**.
48
+ - Card do Kanban passa a abrir os detalhes no **clique simples** (antes era
49
+ duplo clique); flag global suprime o clique disparado no pointerup após um
50
+ drag, então abrir detalhes e arrastar convivem sem conflito.
51
+ - Modal "Detalhes do Lead" exibe **todos os dados** — inclusive `extras`
52
+ (Site, Endereço, Avaliação, Seguidores, Username, Bio), tags, fonte e data
53
+ de criação — com **inputs de edição** para Nome/Telefone/E-mail pré-preenchidos
54
+ (vermelho + mensagem se o nome for apagado), textarea de observações e botão
55
+ **"Salvar Alterações"** grande em gradiente (Fitts + von Restorff), com
56
+ **spinner** durante o salvamento (Zeigarnik), toast de sucesso e
57
+ **atualização automática** do Kanban. O "Fechar" (X) permanece sutil.
58
+ - **5 novos testes pytest** (`backend/tests/test_lead_edit_routes.py`): edição
59
+ completa, edição parcial (campos omitidos preservados), 404, nome vazio (400)
60
+ e payload sem campos editáveis (400).
61
+
40
62
  ## [0.1.24] — 2026-11-09
41
63
 
42
64
  ### Corrigido
package/backend/main.py CHANGED
@@ -344,6 +344,24 @@ def crm_mover_lead(lead_id: str, dados: dict):
344
344
  return atualizado
345
345
 
346
346
 
347
+ @app.put("/api/crm/leads/{lead_id}")
348
+ def crm_editar_lead(lead_id: str, dados: dict):
349
+ """Edita os dados principais do lead (modal de detalhes do CRM).
350
+
351
+ Payload aceita qualquer subconjunto de {nome, telefone, email, ...}; o nome,
352
+ quando presente, não pode ficar vazio (prevenção de erros).
353
+ """
354
+ if "nome" in dados and not str(dados.get("nome") or "").strip():
355
+ raise HTTPException(400, "O nome do lead não pode ficar vazio.")
356
+ patch = {k: v for k, v in dados.items() if k in ("nome", "telefone", "email")}
357
+ if not patch:
358
+ raise HTTPException(400, "Nenhum campo editável informado (nome, telefone, email).")
359
+ atualizado = storage.update_lead(lead_id, patch)
360
+ if not atualizado:
361
+ raise HTTPException(404, "Lead não encontrado.")
362
+ return atualizado
363
+
364
+
347
365
  # ---------------------------------------------------------------------------
348
366
  # Campanhas / Disparos
349
367
  # ---------------------------------------------------------------------------
@@ -0,0 +1,63 @@
1
+ """Testes da edição do lead — PUT /api/crm/leads/{lead_id}.
2
+
3
+ Edição de nome/telefone/email (todos opcionais), persistência, 404 para ID
4
+ inexistente e bloqueio de nome vazio (prevenção de erros).
5
+ """
6
+
7
+ import pytest
8
+ from fastapi.testclient import TestClient
9
+
10
+ import main
11
+
12
+
13
+ @pytest.fixture()
14
+ def client(tmp_path, monkeypatch):
15
+ monkeypatch.setenv("LEADMASTER_HOME", str(tmp_path))
16
+ with TestClient(main.app) as c:
17
+ yield c
18
+
19
+
20
+ def _criar_lead(client):
21
+ return client.post("/api/crm/leads", json={"nome": "Lead Original", "telefone": "(11) 90000-0000", "email": "a@b.com"}).json()
22
+
23
+
24
+ def test_editar_campos_principais(client):
25
+ lead = _criar_lead(client)
26
+ r = client.put(
27
+ f"/api/crm/leads/{lead['id']}",
28
+ json={"nome": "Lead Editado", "telefone": "(21) 98888-7777", "email": "novo@empresa.com"},
29
+ )
30
+ assert r.status_code == 200
31
+ corpo = r.json()
32
+ assert corpo["nome"] == "Lead Editado"
33
+ assert corpo["telefone"] == "(21) 98888-7777"
34
+ assert corpo["email"] == "novo@empresa.com"
35
+ # Persistido no leads.json (a listagem reflete a edição).
36
+ salvo = [l for l in client.get("/api/crm/leads").json() if l["id"] == lead["id"]][0]
37
+ assert salvo["nome"] == "Lead Editado"
38
+
39
+
40
+ def test_editar_parcial(client):
41
+ lead = _criar_lead(client)
42
+ r = client.put(f"/api/crm/leads/{lead['id']}", json={"email": "parcial@x.com"})
43
+ assert r.status_code == 200
44
+ assert r.json()["email"] == "parcial@x.com"
45
+ assert r.json()["nome"] == "Lead Original" # campos omitidos permanecem
46
+
47
+
48
+ def test_editar_inexistente_404(client):
49
+ r = client.put("/api/crm/leads/nao-existe", json={"nome": "X"})
50
+ assert r.status_code == 404
51
+
52
+
53
+ def test_nome_vazio_bloqueado(client):
54
+ lead = _criar_lead(client)
55
+ r = client.put(f"/api/crm/leads/{lead['id']}", json={"nome": " "})
56
+ assert r.status_code == 400
57
+ assert "vazio" in r.json()["detail"]
58
+
59
+
60
+ def test_payload_sem_campos_editaveis(client):
61
+ lead = _criar_lead(client)
62
+ r = client.put(f"/api/crm/leads/{lead['id']}", json={"etapa": "fechado"})
63
+ assert r.status_code == 400