feat(email): adiciona templates React Email e melhora UI admin
Some checks failed
CI/CD Web + Desktop / Detect changes (push) Successful in 7s
CI/CD Web + Desktop / Deploy (VPS Linux) (push) Successful in 3m33s
Quality Checks / Lint, Test and Build (push) Successful in 3m41s
CI/CD Web + Desktop / Deploy Convex functions (push) Has been cancelled

- Cria 10 novos templates React Email (invite, password-reset, new-login,
  sla-warning, sla-breached, ticket-created, ticket-resolved,
  ticket-assigned, ticket-status, ticket-comment)
- Adiciona envio de email ao criar convite de usuario
- Adiciona security_invite em COLLABORATOR_VISIBLE_TYPES
- Melhora tabela de equipe com badges de papel e colunas fixas
- Atualiza TicketCard com nova interface de props
- Remove botao de limpeza de dados antigos do admin

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
rever-tecnologia 2025-12-17 11:46:02 -03:00
parent 8546a1feb1
commit 498b9789b5
17 changed files with 1422 additions and 190 deletions

View file

@ -14,6 +14,18 @@ export type TicketCardData = {
assigneeName?: string | null
}
export type TicketCardProps = {
ticketNumber: string
ticketTitle: string
status?: string | null
priority?: string | null
category?: string | null
subcategory?: string | null
companyName?: string | null
requesterName?: string | null
assigneeName?: string | null
}
function badge(label: string, bg: string, color: string) {
return (
<span
@ -76,7 +88,8 @@ function Row({ label, value }: { label: string; value: React.ReactNode }) {
)
}
export function TicketCard({ ticket }: { ticket: TicketCardData }) {
/** @deprecated Use TicketCard with props instead */
export function TicketCardLegacy({ ticket }: { ticket: TicketCardData }) {
return (
<Section
style={{
@ -100,3 +113,90 @@ export function TicketCard({ ticket }: { ticket: TicketCardData }) {
</Section>
)
}
export function TicketCard(props: TicketCardProps) {
const { ticketNumber, ticketTitle, status, priority, category, subcategory, companyName, requesterName, assigneeName } = props
const categoryLabel = category && subcategory ? `${category} / ${subcategory}` : category ?? subcategory ?? null
return (
<Section
style={{
backgroundColor: "#f8fafc",
borderRadius: "12px",
border: `1px solid ${EMAIL_COLORS.border}`,
margin: "24px 0",
}}
>
<table cellPadding="0" cellSpacing="0" role="presentation" style={{ width: "100%" }}>
<tbody>
<tr>
<td style={{ padding: "16px 20px", borderBottom: "1px solid #f1f5f9" }}>
<Text style={{ margin: 0, fontSize: "13px", fontWeight: 600, color: EMAIL_COLORS.textMuted }}>
Chamado #{ticketNumber}
</Text>
<Text style={{ margin: "4px 0 0 0", fontSize: "16px", fontWeight: 700, color: EMAIL_COLORS.textPrimary }}>
{ticketTitle}
</Text>
</td>
</tr>
<tr>
<td style={{ padding: "16px 20px" }}>
<table cellPadding="0" cellSpacing="0" role="presentation" style={{ width: "100%" }}>
<tbody>
{status ? (
<tr>
<td style={{ paddingBottom: "10px", width: "100px", color: EMAIL_COLORS.textMuted, fontSize: "13px", fontWeight: 500 }}>
Status
</td>
<td style={{ paddingBottom: "10px" }}>{statusBadge(status)}</td>
</tr>
) : null}
{priority ? (
<tr>
<td style={{ paddingBottom: "10px", width: "100px", color: EMAIL_COLORS.textMuted, fontSize: "13px", fontWeight: 500 }}>
Prioridade
</td>
<td style={{ paddingBottom: "10px" }}>{priorityBadge(priority)}</td>
</tr>
) : null}
{categoryLabel ? (
<tr>
<td style={{ paddingBottom: "10px", width: "100px", color: EMAIL_COLORS.textMuted, fontSize: "13px", fontWeight: 500 }}>
Categoria
</td>
<td style={{ paddingBottom: "10px", color: EMAIL_COLORS.textPrimary, fontSize: "14px" }}>{categoryLabel}</td>
</tr>
) : null}
{companyName ? (
<tr>
<td style={{ paddingBottom: "10px", width: "100px", color: EMAIL_COLORS.textMuted, fontSize: "13px", fontWeight: 500 }}>
Empresa
</td>
<td style={{ paddingBottom: "10px", color: EMAIL_COLORS.textPrimary, fontSize: "14px" }}>{companyName}</td>
</tr>
) : null}
{requesterName ? (
<tr>
<td style={{ paddingBottom: "10px", width: "100px", color: EMAIL_COLORS.textMuted, fontSize: "13px", fontWeight: 500 }}>
Solicitante
</td>
<td style={{ paddingBottom: "10px", color: EMAIL_COLORS.textPrimary, fontSize: "14px" }}>{requesterName}</td>
</tr>
) : null}
{assigneeName ? (
<tr>
<td style={{ width: "100px", color: EMAIL_COLORS.textMuted, fontSize: "13px", fontWeight: 500 }}>
Responsavel
</td>
<td style={{ color: EMAIL_COLORS.textPrimary, fontSize: "14px" }}>{assigneeName}</td>
</tr>
) : null}
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</Section>
)
}