Skip to content

feat(crm): ficha de informações do contato + correções de layout mobile#61

Merged
sejaanomalo-web merged 1 commit into
mainfrom
claude/crm-info-contato-mobile-fixes
Jul 13, 2026
Merged

feat(crm): ficha de informações do contato + correções de layout mobile#61
sejaanomalo-web merged 1 commit into
mainfrom
claude/crm-info-contato-mobile-fixes

Conversation

@sejaanomalo-web

@sejaanomalo-web sejaanomalo-web commented Jul 13, 2026

Copy link
Copy Markdown
Owner

Adiciona botão de informações do contato (nome, telefone, e-mail, notas com formatação básica e campos personalizados) tanto no Kanban (popup) quanto em Conversas (painel embutido na própria thread, com X pra voltar). Corrige scroll horizontal indevido no Kanban/Calendário/popovers no mobile, empilha compromissos+calendário no Calendário em telas pequenas, e reorganiza os botões de ação em massa do painel de notificações numa toolbar própria.

Summary by CodeRabbit

  • New Features

    • Added editable contact information panels for CRM leads, including name, email, notes, and custom fields.
    • Added contact information access from Kanban cards and conversation threads.
    • Improved notification actions with a dedicated toolbar and “Mark as read” option.
  • Responsive Design

    • Improved mobile layouts for calendars, contact menus, tag pickers, and new-contact panels.
    • Prevented horizontal scrolling on mobile CRM screens.
    • Enhanced Kanban touch scrolling and overflow behavior.

Adiciona botão de informações do contato (nome, telefone, e-mail, notas com
formatação básica e campos personalizados) tanto no Kanban (popup) quanto em
Conversas (painel embutido na própria thread, com X pra voltar). Corrige
scroll horizontal indevido no Kanban/Calendário/popovers no mobile, empilha
compromissos+calendário no Calendário em telas pequenas, e reorganiza os
botões de ação em massa do painel de notificações numa toolbar própria.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
metas-anomalo Ready Ready Preview, Comment Jul 13, 2026 11:14pm

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds editable CRM lead contact information with notes and custom fields, backed by a sanitized server action and database migration. Integrates the editor into Kanban and threads, while updating CRM mobile layouts, popovers, calendar panes, scrolling, and notification controls.

Changes

Contact information editing

Layer / File(s) Summary
Contact data contract and storage
supabase/migrations/..., lib/crm-leads.ts
Adds lead note and custom-field storage columns plus the CampoPersonalizado type.
Contact update server action
lib/crm-leads-actions.ts
Validates and persists contact data, sanitizes notes HTML, and normalizes custom fields.
Contact editor and CRM entry points
components/crm/InformacoesContato.tsx, components/crm/Kanban.tsx, components/crm/Thread.tsx
Adds the contact editor and opens it from Kanban cards or the thread header.

Responsive CRM interface

Layer / File(s) Summary
Mobile calendar layout
app/globals.css, components/crm/Calendario.tsx
Stacks calendar panes on mobile, reorders them, constrains widths, and limits pane heights.
Responsive CRM controls
components/crm/Etiquetas.tsx, components/crm/NovoContato.tsx, components/crm/Thread.tsx, components/crm/Kanban.tsx
Makes popovers responsive and adjusts Kanban sizing and touch scrolling.
Notification action toolbar
components/SinoNotificacoes.tsx
Separates close and mass actions into distinct controls and updates the list divider.
CRM mobile overflow guard
app/globals.css
Disables horizontal scrolling in the CRM fullscreen mobile context.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant CRMInterface
  participant InformacoesContato
  participant editarInformacoesContatoAction
  participant crm_leads
  User->>CRMInterface: Open contact information
  CRMInterface->>InformacoesContato: Render lead editor
  User->>InformacoesContato: Edit and save contact data
  InformacoesContato->>editarInformacoesContatoAction: Submit FormData
  editarInformacoesContatoAction->>crm_leads: Validate and update lead
  editarInformacoesContatoAction-->>InformacoesContato: Return result
  InformacoesContato-->>User: Refresh and close or show error
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed O título resume bem a adição da ficha de informações do contato e as correções de layout mobile.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/crm-info-contato-mobile-fixes

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/crm-leads-actions.ts (1)

1-1: 🔒 Security & Privacy | 🔴 Critical | 🏗️ Heavy lift

Stored XSS in contact notes sanitizarHtmlContato still lets browser-accepted / separators through (for example <img/onerror=alert(1)>), and components/crm/InformacoesContato.tsx renders the saved HTML with dangerouslySetInnerHTML. Replace the regex sanitizer with a parser-backed allowlist sanitizer.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/crm-leads-actions.ts` at line 1, Replace the regex-based sanitization in
sanitizarHtmlContato with a parser-backed HTML allowlist sanitizer that rejects
browser-valid tag separators such as `/` and permits only explicitly approved
tags, attributes, and URL schemes. Ensure the sanitized output remains safe for
InformacoesContato.tsx before it is passed to dangerouslySetInnerHTML.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/globals.css`:
- Around line 710-715: Update the JSX layout in Calendario so the commitments
pane is rendered before the calendar pane, matching the mobile visual order and
preserving accessibility navigation; then apply explicit desktop flex ordering
so the intended desktop arrangement remains unchanged, using the pane classes
crm-calendario-compromissos-pane and crm-calendario-mes-pane.

In `@components/crm/Kanban.tsx`:
- Around line 799-835: Move the info button currently rendered in the Link card
content outside the Link, making it a sibling overlay within a relative card
wrapper. Preserve the existing onClick, onPointerDown, accessibility attributes,
and styling, and ensure the wrapper provides the positioning context required by
the absolute button.

In `@lib/crm-leads-actions.ts`:
- Around line 35-66: Replace the regex-based implementation in
sanitizarHtmlContato with a real HTML parser/sanitizer that safely handles
malformed tags such as img/onerror payloads, removes disallowed elements and
attributes, and preserves only the existing basic formatting allowlist. Apply
the sanitizer before notas_html is stored or rendered, while retaining the
20,000-character limit.

---

Outside diff comments:
In `@lib/crm-leads-actions.ts`:
- Line 1: Replace the regex-based sanitization in sanitizarHtmlContato with a
parser-backed HTML allowlist sanitizer that rejects browser-valid tag separators
such as `/` and permits only explicitly approved tags, attributes, and URL
schemes. Ensure the sanitized output remains safe for InformacoesContato.tsx
before it is passed to dangerouslySetInnerHTML.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c2eef343-fd12-43fc-821e-e4bc40be2d22

📥 Commits

Reviewing files that changed from the base of the PR and between df5a8f2 and dd6eb48.

📒 Files selected for processing (11)
  • app/globals.css
  • components/SinoNotificacoes.tsx
  • components/crm/Calendario.tsx
  • components/crm/Etiquetas.tsx
  • components/crm/InformacoesContato.tsx
  • components/crm/Kanban.tsx
  • components/crm/NovoContato.tsx
  • components/crm/Thread.tsx
  • lib/crm-leads-actions.ts
  • lib/crm-leads.ts
  • supabase/migrations/20260716_crm_fase7_info_contato.sql

Comment thread app/globals.css
Comment on lines +710 to +715
.crm-calendario-mes-pane {
order: 2;
max-height: 40vh;
}
.crm-calendario-compromissos-pane {
order: 1;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Keep the DOM order aligned with the mobile visual order.

The commitments pane is visually moved before the calendar with order, but components/crm/Calendario.tsx still renders the calendar first. Screen readers and other DOM-based navigation will therefore encounter the calendar before the commitments panel despite the opposite visual order. Render commitments first in the DOM and apply explicit desktop ordering, or avoid reordering the content with CSS.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/globals.css` around lines 710 - 715, Update the JSX layout in Calendario
so the commitments pane is rendered before the calendar pane, matching the
mobile visual order and preserving accessibility navigation; then apply explicit
desktop flex ordering so the intended desktop arrangement remains unchanged,
using the pane classes crm-calendario-compromissos-pane and
crm-calendario-mes-pane.

Comment thread components/crm/Kanban.tsx
Comment on lines +799 to +835
{onAbrirInfo && (
<button
type="button"
// preventDefault+stopPropagation evita navegar pro Link e (via
// stopPropagation, que o React aplica na fase de bubbling do
// synthetic event antes de chegar no <Link>) evita disparar o
// drag do dnd-kit, cujos listeners ficam no wrapper acima.
onClick={(e) => {
e.preventDefault()
e.stopPropagation()
onAbrirInfo(lead)
}}
onPointerDown={(e) => e.stopPropagation()}
title="Informações do contato"
aria-label="Informações do contato"
style={{
position: "absolute",
top: 6,
right: 6,
width: 20,
height: 20,
display: "flex",
alignItems: "center",
justifyContent: "center",
borderRadius: 6,
fontSize: 11,
lineHeight: 1,
color: "var(--text-4)",
background: "rgba(0,0,0,0.25)",
}}
>
</button>
)}
<div className="flex items-center gap-2">
<Avatar nome={nomeExibido} cor={cor} fotoUrl={lead.foto_url} size={26} />
<div className="min-w-0 flex-1">
<div className="min-w-0 flex-1" style={{ paddingRight: onAbrirInfo ? 22 : 0 }}>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the target file structure, then inspect the relevant ranges.
ast-grep outline components/crm/Kanban.tsx --view expanded || true
printf '\n---\n'
sed -n '760,860p' components/crm/Kanban.tsx | cat -n

Repository: sejaanomalo-web/metas-anomalo

Length of output: 4217


Move the info button outside the Link.
The nested <button> inside <Link> renders invalid interactive-in-interactive HTML and can lead to inconsistent keyboard/screen-reader behavior. Make the card wrapper relative and render the info button as a sibling overlay instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/crm/Kanban.tsx` around lines 799 - 835, Move the info button
currently rendered in the Link card content outside the Link, making it a
sibling overlay within a relative card wrapper. Preserve the existing onClick,
onPointerDown, accessibility attributes, and styling, and ensure the wrapper
provides the positioning context required by the absolute button.

Comment thread lib/crm-leads-actions.ts
Comment on lines +35 to +66
// Tags permitidas nas notas do contato — só o suficiente pro editor de
// formatação básica (negrito/itálico/sublinhado/lista). Tudo mais (script,
// style, atributos como onclick/style/href) é removido: o HTML vem do
// contentEditable do navegador, então precisa ser tratado como input não
// confiável antes de ir pro banco.
const TAGS_PERMITIDAS_NOTAS = new Set([
"b", "strong", "i", "em", "u", "ul", "ol", "li", "br", "p", "div", "span",
])

// Casa uma tag inteira (com atributos) tratando valores entre aspas como
// átomos — assim um atributo tipo title="a>b" não corta o match no '>' de
// dentro da aspa (armadilha comum de sanitizador ingênuo baseado em regex).
const TAG_COM_ATRIBUTOS =
/<\/?([a-zA-Z0-9]+)(?:\s+[a-zA-Z0-9:_-]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s"'>]+))?)*\s*\/?>/g

function sanitizarHtmlContato(bruto: string): string {
let limpo = bruto.replace(/<!--[\s\S]*?-->/g, "")
// Blocos perigosos somem inteiros (tag + conteúdo) antes de tudo — o resto
// vira texto puro pela troca de tags abaixo, então script/style nunca
// chegam a executar nem a poluir a nota com CSS/JS cru.
limpo = limpo.replace(
/<(script|style|iframe|object|embed|link|meta|form|svg)[^>]*>[\s\S]*?<\/\1>/gi,
""
)
limpo = limpo.replace(TAG_COM_ATRIBUTOS, (tagCompleta, nomeTag) => {
const nome = String(nomeTag).toLowerCase()
if (!TAGS_PERMITIDAS_NOTAS.has(nome)) return ""
const fechamento = tagCompleta.startsWith("</") ? "/" : ""
return `<${fechamento}${nome}>`
})
return limpo.slice(0, 20_000)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🔴 Critical | 🏗️ Heavy lift

Regex HTML sanitization is bypassable and allows stored XSS.

TAG_COM_ATRIBUTOS misses malformed tags like <img/onerror=alert(1)>, so the payload survives sanitizarHtmlContato() and is later rendered via dangerouslySetInnerHTML. Replace this regex-based allowlist with a real HTML sanitizer/parser before storing or rendering notas_html.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/crm-leads-actions.ts` around lines 35 - 66, Replace the regex-based
implementation in sanitizarHtmlContato with a real HTML parser/sanitizer that
safely handles malformed tags such as img/onerror payloads, removes disallowed
elements and attributes, and preserves only the existing basic formatting
allowlist. Apply the sanitizer before notas_html is stored or rendered, while
retaining the 20,000-character limit.

@sejaanomalo-web
sejaanomalo-web merged commit 0f39147 into main Jul 13, 2026
3 checks passed
@sejaanomalo-web
sejaanomalo-web deleted the claude/crm-info-contato-mobile-fixes branch July 13, 2026 23:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant