fix(email-action): corrige cores e acentuação, adiciona drag and drop

- Badges de variáveis agora com fundo preto e texto branco
- Corrige todos os textos sem acentuação (Referência, Título, etc.)
- Adiciona suporte a drag and drop das badges de variáveis

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
esdrasrenan 2025-12-14 00:00:36 -03:00
parent 81e4b528d3
commit 2ab6ed595c

View file

@ -46,24 +46,24 @@ type EmailActionConfigProps = {
agents: Agent[] agents: Agent[]
} }
// Variaveis disponiveis para interpolacao // Variáveis disponíveis para interpolação
const EMAIL_VARIABLES = [ const EMAIL_VARIABLES = [
{ key: "ticket.reference", label: "Referencia", description: "Numero do chamado (ex: #1234)" }, { key: "ticket.reference", label: "Referência", description: "Número do chamado (ex: #1234)" },
{ key: "ticket.subject", label: "Assunto", description: "Titulo do chamado" }, { key: "ticket.subject", label: "Assunto", description: "Título do chamado" },
{ key: "ticket.status", label: "Status", description: "Status atual do chamado" }, { key: "ticket.status", label: "Status", description: "Status atual do chamado" },
{ key: "ticket.priority", label: "Prioridade", description: "Nivel de prioridade" }, { key: "ticket.priority", label: "Prioridade", description: "Nível de prioridade" },
{ key: "company.name", label: "Empresa", description: "Nome da empresa do solicitante" }, { key: "company.name", label: "Empresa", description: "Nome da empresa do solicitante" },
{ key: "requester.name", label: "Solicitante", description: "Nome de quem abriu o chamado" }, { key: "requester.name", label: "Solicitante", description: "Nome de quem abriu o chamado" },
{ key: "assignee.name", label: "Responsavel", description: "Nome do agente responsavel" }, { key: "assignee.name", label: "Responsável", description: "Nome do agente responsável" },
] as const ] as const
type EmailVariable = (typeof EMAIL_VARIABLES)[number] type EmailVariable = (typeof EMAIL_VARIABLES)[number]
const CLEAR_SELECT_VALUE = "__clear__" const CLEAR_SELECT_VALUE = "__clear__"
// Estilos do badge de variavel (cyan para consistencia com o projeto) // Estilos do badge de variável (fundo preto com texto branco)
const VARIABLE_BADGE_CLASSES = const VARIABLE_BADGE_CLASSES =
"inline-flex items-center gap-1 rounded-md bg-cyan-50/60 border border-cyan-200/60 px-1.5 py-0.5 text-xs font-mono text-cyan-700 whitespace-nowrap" "inline-flex items-center gap-1 rounded-md bg-neutral-900 border border-neutral-700 px-1.5 py-0.5 text-xs font-mono text-white whitespace-nowrap"
// Extensao TipTap para variaveis de e-mail // Extensao TipTap para variaveis de e-mail
const EmailVariableMentionExtension = Mention.extend({ const EmailVariableMentionExtension = Mention.extend({
@ -280,7 +280,7 @@ function EmailVariableList({ items, command, onRegister }: EmailVariableListProp
type="button" type="button"
className={cn( className={cn(
"flex w-full flex-col gap-0.5 rounded-md px-3 py-2 text-left transition", "flex w-full flex-col gap-0.5 rounded-md px-3 py-2 text-left transition",
index === selectedIndex ? "bg-cyan-50/60" : "hover:bg-slate-50" index === selectedIndex ? "bg-neutral-100" : "hover:bg-slate-50"
)} )}
onMouseEnter={() => setSelectedIndex(index)} onMouseEnter={() => setSelectedIndex(index)}
onMouseDown={(e) => { onMouseDown={(e) => {
@ -288,7 +288,7 @@ function EmailVariableList({ items, command, onRegister }: EmailVariableListProp
selectItem(index) selectItem(index)
}} }}
> >
<span className="font-mono text-sm text-cyan-700">{`{{${item.key}}}`}</span> <span className="font-mono text-sm text-neutral-900">{`{{${item.key}}}`}</span>
<span className="text-xs text-muted-foreground">{item.description}</span> <span className="text-xs text-muted-foreground">{item.description}</span>
</button> </button>
))} ))}
@ -440,11 +440,11 @@ export function EmailActionConfig({ action, onChange, onRemove, agents }: EmailA
return ( return (
<div className="space-y-4"> <div className="space-y-4">
{/* Header com tipo e botao de remover */} {/* Header com tipo e botão de remover */}
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<div className="flex size-8 items-center justify-center rounded-lg bg-cyan-50/60"> <div className="flex size-8 items-center justify-center rounded-lg bg-neutral-900">
<Braces className="size-4 text-cyan-600" /> <Braces className="size-4 text-white" />
</div> </div>
<span className="font-medium text-neutral-900">Enviar e-mail</span> <span className="font-medium text-neutral-900">Enviar e-mail</span>
</div> </div>
@ -454,7 +454,7 @@ export function EmailActionConfig({ action, onChange, onRemove, agents }: EmailA
size="icon" size="icon"
onClick={onRemove} onClick={onRemove}
className="h-8 w-8 text-slate-500 hover:bg-red-50 hover:text-red-700" className="h-8 w-8 text-slate-500 hover:bg-red-50 hover:text-red-700"
title="Remover acao" title="Remover ação"
> >
<Trash2 className="size-4" /> <Trash2 className="size-4" />
</Button> </Button>
@ -486,10 +486,10 @@ export function EmailActionConfig({ action, onChange, onRemove, agents }: EmailA
</div> </div>
</div> </div>
{/* Paleta de variaveis */} {/* Paleta de variáveis */}
<div className="space-y-2"> <div className="space-y-2">
<Label className="text-xs text-muted-foreground"> <Label className="text-xs text-muted-foreground">
Variaveis disponiveis (clique para inserir no {activeField === "subject" ? "assunto" : "corpo"}) Variáveis disponíveis (arraste ou clique para inserir no {activeField === "subject" ? "assunto" : "corpo"})
</Label> </Label>
<div className="flex flex-wrap gap-1.5"> <div className="flex flex-wrap gap-1.5">
{EMAIL_VARIABLES.map((variable) => ( {EMAIL_VARIABLES.map((variable) => (
@ -497,10 +497,15 @@ export function EmailActionConfig({ action, onChange, onRemove, agents }: EmailA
<TooltipTrigger asChild> <TooltipTrigger asChild>
<button <button
type="button" type="button"
draggable
onClick={() => handleInsertVariable(variable)} onClick={() => handleInsertVariable(variable)}
onDragStart={(e) => {
e.dataTransfer.setData("text/plain", `{{${variable.key}}}`)
e.dataTransfer.effectAllowed = "copy"
}}
className={cn( className={cn(
VARIABLE_BADGE_CLASSES, VARIABLE_BADGE_CLASSES,
"cursor-pointer transition hover:bg-cyan-100/60 hover:border-cyan-300/60" "cursor-grab transition hover:bg-neutral-800 active:cursor-grabbing"
)} )}
> >
{`{{${variable.key}}}`} {`{{${variable.key}}}`}
@ -514,9 +519,9 @@ export function EmailActionConfig({ action, onChange, onRemove, agents }: EmailA
</div> </div>
</div> </div>
{/* Destinatarios */} {/* Destinatários */}
<div className="space-y-3 rounded-lg border border-slate-200 bg-slate-50/50 p-4"> <div className="space-y-3 rounded-lg border border-slate-200 bg-slate-50/50 p-4">
<Label className="text-sm font-medium">Destinatarios</Label> <Label className="text-sm font-medium">Destinatários</Label>
<div className="flex flex-wrap gap-4"> <div className="flex flex-wrap gap-4">
<label className="flex items-center gap-2 text-sm text-neutral-700"> <label className="flex items-center gap-2 text-sm text-neutral-700">
@ -531,13 +536,13 @@ export function EmailActionConfig({ action, onChange, onRemove, agents }: EmailA
checked={action.toAssignee} checked={action.toAssignee}
onCheckedChange={(checked) => handleChange("toAssignee", Boolean(checked))} onCheckedChange={(checked) => handleChange("toAssignee", Boolean(checked))}
/> />
Responsavel do ticket Responsável do ticket
</label> </label>
</div> </div>
<div className="grid gap-3 sm:grid-cols-2"> <div className="grid gap-3 sm:grid-cols-2">
<div className="space-y-1.5"> <div className="space-y-1.5">
<Label className="text-xs text-muted-foreground">Agente especifico (opcional)</Label> <Label className="text-xs text-muted-foreground">Agente específico (opcional)</Label>
<Select <Select
value={action.toUserId} value={action.toUserId}
onValueChange={(value) => { onValueChange={(value) => {
@ -551,8 +556,8 @@ export function EmailActionConfig({ action, onChange, onRemove, agents }: EmailA
<SelectContent className="rounded-xl"> <SelectContent className="rounded-xl">
{agents.length === 0 ? ( {agents.length === 0 ? (
<SelectEmptyState <SelectEmptyState
message="Nenhum agente disponivel" message="Nenhum agente disponível"
createLabel="Gerenciar usuarios" createLabel="Gerenciar usuários"
createHref="/admin/users" createHref="/admin/users"
/> />
) : ( ) : (
@ -581,10 +586,10 @@ export function EmailActionConfig({ action, onChange, onRemove, agents }: EmailA
</div> </div>
</div> </div>
{/* Botao do e-mail */} {/* Botão do e-mail */}
<div className="grid gap-3 sm:grid-cols-2"> <div className="grid gap-3 sm:grid-cols-2">
<div className="space-y-1.5"> <div className="space-y-1.5">
<Label className="text-xs text-muted-foreground">Link do botao</Label> <Label className="text-xs text-muted-foreground">Link do botão</Label>
<Select <Select
value={action.ctaTarget} value={action.ctaTarget}
onValueChange={(value) => handleChange("ctaTarget", value as EmailCtaTarget)} onValueChange={(value) => handleChange("ctaTarget", value as EmailCtaTarget)}
@ -601,7 +606,7 @@ export function EmailActionConfig({ action, onChange, onRemove, agents }: EmailA
</div> </div>
<div className="space-y-1.5"> <div className="space-y-1.5">
<Label className="text-xs text-muted-foreground">Texto do botao</Label> <Label className="text-xs text-muted-foreground">Texto do botão</Label>
<Input <Input
value={action.ctaLabel} value={action.ctaLabel}
onChange={(e) => handleChange("ctaLabel", e.target.value)} onChange={(e) => handleChange("ctaLabel", e.target.value)}