2026-05-26 09:08:08 -03:00
|
|
|
|
import { useEffect, useMemo, useState } from 'react';
|
2026-05-22 10:51:07 -03:00
|
|
|
|
import { DataPanel } from './DataPanel';
|
|
|
|
|
|
import {
|
|
|
|
|
|
approveTemplateByAdmin,
|
|
|
|
|
|
deleteTemplate,
|
|
|
|
|
|
listTemplates,
|
|
|
|
|
|
rejectTemplateByAdmin,
|
|
|
|
|
|
saveTemplate,
|
|
|
|
|
|
} from '../services/templateService';
|
|
|
|
|
|
|
|
|
|
|
|
const fieldStyle = {
|
|
|
|
|
|
width: '100%',
|
|
|
|
|
|
border: '1px solid var(--color-border)',
|
|
|
|
|
|
borderRadius: '14px',
|
|
|
|
|
|
padding: '0.75rem 0.85rem',
|
|
|
|
|
|
background: '#fff',
|
|
|
|
|
|
color: 'var(--color-text)',
|
|
|
|
|
|
fontWeight: 600,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const statusMeta = {
|
|
|
|
|
|
approved: {
|
|
|
|
|
|
label: 'Aprovado pela Meta',
|
|
|
|
|
|
background: 'rgba(34, 197, 94, 0.12)',
|
|
|
|
|
|
color: '#15803d',
|
|
|
|
|
|
},
|
|
|
|
|
|
meta_review: {
|
|
|
|
|
|
label: 'Em análise pela Meta',
|
|
|
|
|
|
background: 'rgba(229, 162, 42, 0.16)',
|
|
|
|
|
|
color: '#8a5a00',
|
|
|
|
|
|
},
|
|
|
|
|
|
admin_review: {
|
|
|
|
|
|
label: 'Aguardando aprovação do admin',
|
|
|
|
|
|
background: 'rgba(0, 49, 80, 0.1)',
|
|
|
|
|
|
color: 'var(--color-primary)',
|
|
|
|
|
|
},
|
|
|
|
|
|
rejected: {
|
|
|
|
|
|
label: 'Reprovado pelo admin',
|
|
|
|
|
|
background: 'rgba(181, 31, 31, 0.1)',
|
|
|
|
|
|
color: 'var(--color-secondary)',
|
|
|
|
|
|
},
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-05-26 09:08:08 -03:00
|
|
|
|
const templateCategories = [
|
|
|
|
|
|
{ id: 'UTILITY', label: 'UTILITY', detail: 'Confirmações, lembretes e atualizações', cost: 'Menor custo' },
|
|
|
|
|
|
{ id: 'MARKETING', label: 'MARKETING', detail: 'Promoções, ofertas e engajamento', cost: 'Maior custo' },
|
|
|
|
|
|
{ id: 'AUTHENTICATION', label: 'AUTHENTICATION', detail: 'OTP e códigos de verificação', cost: 'Menor custo' },
|
|
|
|
|
|
];
|
|
|
|
|
|
|
2026-05-22 10:51:07 -03:00
|
|
|
|
function getTemplateStatus(template) {
|
|
|
|
|
|
return statusMeta[template.status] || statusMeta.approved;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function getRemainingMetaText(template) {
|
|
|
|
|
|
if (template.status !== 'meta_review' || !template.meta_submitted_at) return '';
|
|
|
|
|
|
const submittedAt = new Date(template.meta_submitted_at).getTime();
|
|
|
|
|
|
const approvedAt = submittedAt + 15 * 60 * 1000;
|
|
|
|
|
|
const remainingMs = approvedAt - Date.now();
|
2026-05-26 09:08:08 -03:00
|
|
|
|
if (remainingMs <= 0) return 'Aprovação disponível ao atualizar.';
|
2026-05-22 10:51:07 -03:00
|
|
|
|
const minutes = Math.ceil(remainingMs / 60000);
|
2026-05-26 09:08:08 -03:00
|
|
|
|
return `Aprovação em aproximadamente ${minutes} min.`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function renderTemplatePreview(content) {
|
|
|
|
|
|
return String(content || 'Digite a mensagem do template...')
|
|
|
|
|
|
.replace(/\{nome\}/gi, 'Ana Paula')
|
|
|
|
|
|
.replace(/\{cliente\}/gi, 'Ana Paula')
|
|
|
|
|
|
.replace(/\{data\}/gi, '26/05/2026')
|
|
|
|
|
|
.replace(/\{link\}/gi, 'https://sothis.com.br/rh')
|
|
|
|
|
|
.replace(/\{variavel\}/gi, 'informação personalizada')
|
|
|
|
|
|
.replace(/\{variável\}/gi, 'informação personalizada');
|
2026-05-22 10:51:07 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function TemplateManagementPanel({
|
|
|
|
|
|
areas = [],
|
|
|
|
|
|
mode = 'admin',
|
|
|
|
|
|
managedAreaNames = [],
|
|
|
|
|
|
isMobile = false,
|
|
|
|
|
|
}) {
|
|
|
|
|
|
const [templates, setTemplates] = useState([]);
|
|
|
|
|
|
const [selectedArea, setSelectedArea] = useState('all');
|
2026-05-26 09:08:08 -03:00
|
|
|
|
const [form, setForm] = useState({ name: '', content: '', areaId: '', category: 'UTILITY' });
|
2026-05-22 10:51:07 -03:00
|
|
|
|
const [statusMessage, setStatusMessage] = useState('');
|
|
|
|
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
|
|
|
|
|
|
|
|
|
|
const isAdmin = mode === 'admin';
|
|
|
|
|
|
const visibleAreas = isAdmin
|
|
|
|
|
|
? areas
|
|
|
|
|
|
: areas.filter((area) => managedAreaNames.includes(area.nome));
|
|
|
|
|
|
|
|
|
|
|
|
const filteredTemplates = useMemo(() => {
|
|
|
|
|
|
return templates.filter((template) => {
|
|
|
|
|
|
const areaMatches = selectedArea === 'all' || String(template.area_id || '') === selectedArea;
|
|
|
|
|
|
const supervisorAreaMatches =
|
|
|
|
|
|
isAdmin ||
|
|
|
|
|
|
!template.area_nome ||
|
|
|
|
|
|
managedAreaNames.includes(template.area_nome);
|
|
|
|
|
|
return areaMatches && supervisorAreaMatches;
|
|
|
|
|
|
});
|
|
|
|
|
|
}, [templates, selectedArea, isAdmin, managedAreaNames]);
|
|
|
|
|
|
|
|
|
|
|
|
async function loadTemplates() {
|
|
|
|
|
|
setIsLoading(true);
|
|
|
|
|
|
try {
|
|
|
|
|
|
const data = await listTemplates();
|
|
|
|
|
|
setTemplates(Array.isArray(data) ? data : []);
|
|
|
|
|
|
setStatusMessage('');
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
setStatusMessage(error.message);
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
setIsLoading(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
loadTemplates();
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
|
|
async function submitTemplate(event) {
|
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
const name = form.name.trim();
|
|
|
|
|
|
const content = form.content.trim();
|
|
|
|
|
|
if (!name || !content) return;
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
await saveTemplate({
|
|
|
|
|
|
name,
|
|
|
|
|
|
content,
|
2026-05-26 09:08:08 -03:00
|
|
|
|
category: form.category,
|
2026-05-22 10:51:07 -03:00
|
|
|
|
areaId: Number(form.areaId) || null,
|
|
|
|
|
|
requestedByRole: isAdmin ? 'admin' : 'supervisor',
|
|
|
|
|
|
});
|
2026-05-26 09:08:08 -03:00
|
|
|
|
setForm({ name: '', content: '', areaId: '', category: 'UTILITY' });
|
2026-05-22 10:51:07 -03:00
|
|
|
|
setStatusMessage(
|
|
|
|
|
|
isAdmin
|
|
|
|
|
|
? 'Template enviado para aprovação.'
|
|
|
|
|
|
: 'Template enviado para aprovação do admin.',
|
|
|
|
|
|
);
|
|
|
|
|
|
await loadTemplates();
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
setStatusMessage(error.message);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function approveTemplate(templateId) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
await approveTemplateByAdmin(templateId);
|
2026-05-26 09:08:08 -03:00
|
|
|
|
setStatusMessage('Template aprovado pelo admin e enviado para análise da Meta.');
|
2026-05-22 10:51:07 -03:00
|
|
|
|
await loadTemplates();
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
setStatusMessage(error.message);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function rejectTemplate(templateId) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
await rejectTemplateByAdmin(templateId);
|
|
|
|
|
|
setStatusMessage('Template reprovado pelo admin.');
|
|
|
|
|
|
await loadTemplates();
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
setStatusMessage(error.message);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function removeTemplate(templateId) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
await deleteTemplate(templateId);
|
|
|
|
|
|
setStatusMessage('Template excluído.');
|
|
|
|
|
|
await loadTemplates();
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
setStatusMessage(error.message);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<section style={{ display: 'grid', gap: '1rem' }}>
|
|
|
|
|
|
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
|
|
|
|
|
|
<label style={{ display: 'grid', gap: '0.35rem', width: isMobile ? '100%' : 280 }}>
|
|
|
|
|
|
<span style={{ fontWeight: 800 }}>Filtrar por especialidade</span>
|
|
|
|
|
|
<select value={selectedArea} onChange={(event) => setSelectedArea(event.target.value)} style={fieldStyle}>
|
|
|
|
|
|
<option value="all">Todas as especialidades</option>
|
|
|
|
|
|
{visibleAreas.map((area) => (
|
|
|
|
|
|
<option key={area.id} value={area.id}>
|
|
|
|
|
|
{area.nome}
|
|
|
|
|
|
</option>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</select>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<DataPanel
|
|
|
|
|
|
title={isAdmin ? 'Templates WhatsApp' : 'Solicitar template'}
|
|
|
|
|
|
description={
|
|
|
|
|
|
isAdmin
|
2026-05-26 09:08:08 -03:00
|
|
|
|
? 'Crie templates e aprove solicitações de supervisores antes do envio para a Meta.'
|
2026-05-22 10:51:07 -03:00
|
|
|
|
: 'Templates enviados por supervisor passam primeiro pela aprovação do admin.'
|
|
|
|
|
|
}
|
|
|
|
|
|
>
|
2026-05-26 09:08:08 -03:00
|
|
|
|
<form onSubmit={submitTemplate} style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : 'minmax(0, 1fr) minmax(300px, 0.55fr)', gap: '1rem', alignItems: 'start' }}>
|
|
|
|
|
|
<div style={{ display: 'grid', gap: '0.85rem' }}>
|
|
|
|
|
|
<div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : 'minmax(0, 0.8fr) minmax(0, 0.7fr) minmax(220px, 0.55fr)', gap: '0.85rem' }}>
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
value={form.name}
|
|
|
|
|
|
onChange={(event) => setForm((current) => ({ ...current, name: event.target.value }))}
|
|
|
|
|
|
placeholder="Identificador do template"
|
|
|
|
|
|
style={fieldStyle}
|
|
|
|
|
|
/>
|
|
|
|
|
|
<select
|
|
|
|
|
|
value={form.areaId}
|
|
|
|
|
|
onChange={(event) => setForm((current) => ({ ...current, areaId: event.target.value }))}
|
|
|
|
|
|
style={fieldStyle}
|
|
|
|
|
|
>
|
|
|
|
|
|
<option value="">Sem especialidade</option>
|
|
|
|
|
|
{visibleAreas.map((area) => (
|
|
|
|
|
|
<option key={area.id} value={area.id}>
|
|
|
|
|
|
{area.nome}
|
|
|
|
|
|
</option>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</select>
|
|
|
|
|
|
<select
|
|
|
|
|
|
value={form.category}
|
|
|
|
|
|
onChange={(event) => setForm((current) => ({ ...current, category: event.target.value }))}
|
|
|
|
|
|
style={fieldStyle}
|
|
|
|
|
|
>
|
|
|
|
|
|
{templateCategories.map((category) => (
|
|
|
|
|
|
<option key={category.id} value={category.id}>
|
|
|
|
|
|
{category.label} - {category.cost}
|
|
|
|
|
|
</option>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</select>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div style={{ display: 'flex', gap: '0.45rem', flexWrap: 'wrap' }}>
|
|
|
|
|
|
{['{nome}', '{data}', '{link}', '{variavel}'].map((variable) => (
|
|
|
|
|
|
<button
|
|
|
|
|
|
key={variable}
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
onClick={() => setForm((current) => ({ ...current, content: `${current.content}${current.content ? ' ' : ''}${variable}` }))}
|
|
|
|
|
|
style={{
|
|
|
|
|
|
border: '1px solid var(--color-border)',
|
|
|
|
|
|
borderRadius: 999,
|
|
|
|
|
|
padding: '0.45rem 0.7rem',
|
|
|
|
|
|
background: '#fff',
|
|
|
|
|
|
color: 'var(--color-primary)',
|
|
|
|
|
|
fontWeight: 800,
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
Adicionar {variable}
|
|
|
|
|
|
</button>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<textarea
|
|
|
|
|
|
value={form.content}
|
|
|
|
|
|
onChange={(event) => setForm((current) => ({ ...current, content: event.target.value }))}
|
|
|
|
|
|
placeholder="Mensagem do template. Ex: Olá, {nome}. Podemos seguir com seu atendimento por aqui?"
|
|
|
|
|
|
rows={6}
|
|
|
|
|
|
style={{ ...fieldStyle, resize: 'vertical', lineHeight: 1.5 }}
|
2026-05-22 10:51:07 -03:00
|
|
|
|
/>
|
2026-05-26 09:08:08 -03:00
|
|
|
|
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="submit"
|
|
|
|
|
|
style={{
|
|
|
|
|
|
border: 'none',
|
|
|
|
|
|
borderRadius: 16,
|
|
|
|
|
|
padding: '0.9rem 1rem',
|
|
|
|
|
|
background: 'var(--color-primary)',
|
|
|
|
|
|
color: '#fff',
|
|
|
|
|
|
fontWeight: 800,
|
|
|
|
|
|
width: 'fit-content',
|
|
|
|
|
|
}}
|
2026-05-22 10:51:07 -03:00
|
|
|
|
>
|
2026-05-26 09:08:08 -03:00
|
|
|
|
{isAdmin ? 'Enviar para aprovação' : 'Enviar para admin'}
|
|
|
|
|
|
</button>
|
2026-05-22 10:51:07 -03:00
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-05-26 09:08:08 -03:00
|
|
|
|
<aside
|
|
|
|
|
|
aria-label="Preview do template no WhatsApp"
|
2026-05-22 10:51:07 -03:00
|
|
|
|
style={{
|
2026-05-26 09:08:08 -03:00
|
|
|
|
borderRadius: 22,
|
|
|
|
|
|
padding: '1rem',
|
|
|
|
|
|
background: 'linear-gradient(180deg, #e8f3ee, #dcefe8)',
|
|
|
|
|
|
border: '1px solid rgba(0, 49, 80, 0.08)',
|
|
|
|
|
|
minHeight: 260,
|
|
|
|
|
|
display: 'grid',
|
|
|
|
|
|
alignContent: 'end',
|
2026-05-22 10:51:07 -03:00
|
|
|
|
}}
|
|
|
|
|
|
>
|
2026-05-26 09:08:08 -03:00
|
|
|
|
<div style={{ display: 'grid', gap: '0.45rem' }}>
|
|
|
|
|
|
<span style={{ color: 'var(--color-text-soft)', fontWeight: 800, fontSize: '0.82rem' }}>
|
|
|
|
|
|
Preview WhatsApp
|
|
|
|
|
|
</span>
|
|
|
|
|
|
<div
|
|
|
|
|
|
style={{
|
|
|
|
|
|
justifySelf: 'end',
|
|
|
|
|
|
maxWidth: '92%',
|
|
|
|
|
|
borderRadius: '16px 16px 4px 16px',
|
|
|
|
|
|
padding: '0.85rem 0.95rem',
|
|
|
|
|
|
background: '#d9fdd3',
|
|
|
|
|
|
color: '#1f2c33',
|
|
|
|
|
|
boxShadow: '0 6px 18px rgba(0, 49, 80, 0.08)',
|
|
|
|
|
|
whiteSpace: 'pre-wrap',
|
|
|
|
|
|
lineHeight: 1.45,
|
|
|
|
|
|
fontSize: '0.94rem',
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
{renderTemplatePreview(form.content)}
|
|
|
|
|
|
<span
|
|
|
|
|
|
style={{
|
|
|
|
|
|
display: 'block',
|
|
|
|
|
|
marginTop: '0.5rem',
|
|
|
|
|
|
textAlign: 'right',
|
|
|
|
|
|
color: 'rgba(31, 44, 51, 0.58)',
|
|
|
|
|
|
fontSize: '0.72rem',
|
|
|
|
|
|
fontWeight: 700,
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
10:42
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</aside>
|
2026-05-22 10:51:07 -03:00
|
|
|
|
</form>
|
|
|
|
|
|
|
|
|
|
|
|
{statusMessage ? (
|
|
|
|
|
|
<div style={{ marginTop: '0.85rem', color: 'var(--color-primary)', fontWeight: 800 }}>
|
|
|
|
|
|
{statusMessage}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
) : null}
|
|
|
|
|
|
</DataPanel>
|
|
|
|
|
|
|
|
|
|
|
|
<DataPanel title="Lista de templates" description={isLoading ? 'Carregando templates...' : 'Status do fluxo de aprovação.'}>
|
|
|
|
|
|
<div style={{ display: 'grid', gap: '0.75rem', maxHeight: 520, overflowY: 'auto', paddingRight: '0.2rem' }}>
|
|
|
|
|
|
{filteredTemplates.map((template) => {
|
|
|
|
|
|
const status = getTemplateStatus(template);
|
|
|
|
|
|
const remainingMetaText = getRemainingMetaText(template);
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<article
|
|
|
|
|
|
key={template.id}
|
|
|
|
|
|
style={{
|
|
|
|
|
|
border: '1px solid var(--color-border)',
|
|
|
|
|
|
borderRadius: 18,
|
|
|
|
|
|
padding: '1rem',
|
|
|
|
|
|
background: '#fff',
|
|
|
|
|
|
display: 'grid',
|
|
|
|
|
|
gap: '0.65rem',
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
<div style={{ display: 'flex', justifyContent: 'space-between', gap: '1rem', flexWrap: 'wrap' }}>
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<strong style={{ display: 'block' }}>{template.name}</strong>
|
|
|
|
|
|
<span style={{ color: 'var(--color-text-soft)', fontSize: '0.9rem' }}>
|
2026-05-26 09:08:08 -03:00
|
|
|
|
{template.area_nome || 'Sem especialidade'} · {template.category || 'UTILITY'}
|
2026-05-22 10:51:07 -03:00
|
|
|
|
</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<span
|
|
|
|
|
|
style={{
|
|
|
|
|
|
width: 'fit-content',
|
|
|
|
|
|
borderRadius: 999,
|
|
|
|
|
|
padding: '0.3rem 0.65rem',
|
|
|
|
|
|
background: status.background,
|
|
|
|
|
|
color: status.color,
|
|
|
|
|
|
fontWeight: 800,
|
|
|
|
|
|
fontSize: '0.82rem',
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
{status.label}
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<p style={{ margin: 0, color: 'var(--color-text-soft)', lineHeight: 1.5 }}>
|
|
|
|
|
|
{template.content}
|
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
{remainingMetaText ? (
|
|
|
|
|
|
<span style={{ color: '#8a5a00', fontWeight: 700 }}>{remainingMetaText}</span>
|
|
|
|
|
|
) : null}
|
|
|
|
|
|
|
|
|
|
|
|
{isAdmin ? (
|
|
|
|
|
|
<div style={{ display: 'flex', gap: '0.55rem', flexWrap: 'wrap' }}>
|
|
|
|
|
|
{template.status === 'admin_review' ? (
|
|
|
|
|
|
<>
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
onClick={() => approveTemplate(template.id)}
|
|
|
|
|
|
style={{
|
|
|
|
|
|
border: 'none',
|
|
|
|
|
|
borderRadius: 14,
|
|
|
|
|
|
padding: '0.75rem 0.9rem',
|
|
|
|
|
|
background: 'var(--color-primary)',
|
|
|
|
|
|
color: '#fff',
|
|
|
|
|
|
fontWeight: 800,
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
Aprovar e enviar para Meta
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
onClick={() => rejectTemplate(template.id)}
|
|
|
|
|
|
style={{
|
|
|
|
|
|
border: 'none',
|
|
|
|
|
|
borderRadius: 14,
|
|
|
|
|
|
padding: '0.75rem 0.9rem',
|
|
|
|
|
|
background: 'rgba(181, 31, 31, 0.1)',
|
|
|
|
|
|
color: 'var(--color-secondary)',
|
|
|
|
|
|
fontWeight: 800,
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
Reprovar
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</>
|
|
|
|
|
|
) : null}
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
onClick={() => removeTemplate(template.id)}
|
|
|
|
|
|
style={{
|
|
|
|
|
|
border: '1px solid rgba(181, 31, 31, 0.22)',
|
|
|
|
|
|
borderRadius: 14,
|
|
|
|
|
|
padding: '0.75rem 0.9rem',
|
|
|
|
|
|
background: '#fff',
|
|
|
|
|
|
color: 'var(--color-secondary)',
|
|
|
|
|
|
fontWeight: 800,
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
Excluir
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
) : null}
|
|
|
|
|
|
</article>
|
|
|
|
|
|
);
|
|
|
|
|
|
})}
|
|
|
|
|
|
|
|
|
|
|
|
{!filteredTemplates.length ? (
|
|
|
|
|
|
<span style={{ color: 'var(--color-text-soft)', fontWeight: 700 }}>
|
|
|
|
|
|
Nenhum template encontrado para o filtro atual.
|
|
|
|
|
|
</span>
|
|
|
|
|
|
) : null}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</DataPanel>
|
|
|
|
|
|
</section>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
2026-05-26 09:08:08 -03:00
|
|
|
|
|