// ========== CONFIG ==========
const SUPABASE_URL = 'https://ftujctzhsitfdlctbohr.supabase.co';
const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImZ0dWpjdHpoc2l0ZmRsY3Rib2hyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Njg0MDQzNzcsImV4cCI6MjA4Mzk4MDM3N30.NivluvmqGq7Jc-zpZHsCdjUxC4GzWiAWoR4Ee0N78GI';
const supabaseClient = window.supabase.createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
const MATRIZ_SIZE = 490;
const MATRIZ_PADDING = 20;
const DRAW_SIZE = MATRIZ_SIZE - (MATRIZ_PADDING * 2);
const RAIO_PONTO = 18;
const RAIO_PG = 22;
const MIN_COORDS_FOR_CLUSTER = 15;
let currentCompany = null;
let currentUser = null;
let matrizData = [];
// Estado dos respondentes individuais (com main_style)
let activeLabels = {};
let uniqueLabelsMap = {};
const predefinedColors = ['#FF5733', '#33FF57', '#5733FF', '#F6D833', '#33F6D8', '#D833F6', '#FF335E', '#5E33FF', '#3EFF33', '#33FFAE'];
let labelColors = {};
let colorIndex = 0;
// Estado dos batches
let batches = [];
let batchData = {};
let activeBatches = {};
// Estado do modal
let amostraAtiva = true;
let tipoSelecionado = null;
function getRandomColor() {
const l = '0123456789ABCDEF';
let c = '#';
for (let i = 0; i < 6; i++) c += l[Math.floor(Math.random() * 16)];
return c;
}
function getColorForLabel(id) {
if (!labelColors[id]) labelColors[id] = colorIndex < predefinedColors.length ? predefinedColors[colorIndex++] : getRandomColor();
return labelColors[id];
}
function calcularPosicaoSVG(f, e, c, a) {
f = parseFloat(f) || 0;
e = parseFloat(e) || 0;
c = parseFloat(c) || 0;
a = parseFloat(a) || 0;
const normalX = (c - a) / 100;
const normalY = (f - e) / 100;
return {
svgX: MATRIZ_PADDING + (DRAW_SIZE / 2) + (normalX * DRAW_SIZE / 2),
svgY: MATRIZ_PADDING + (DRAW_SIZE / 2) - (normalY * DRAW_SIZE / 2)
};
}
// ========== INIT ==========
async function initDash() {
try {
const { data: { session }, error: se } = await supabaseClient.auth.getSession();
if (se || !session) { window.location.href = '/dash/login'; return; }
currentUser = session.user;
const { data: cd, error: ce } = await supabaseClient.rpc('get_current_company');
if (ce || !cd.success) { await supabaseClient.auth.signOut(); window.location.href = '/dash/login'; return; }
currentCompany = cd.company;
updateHeader();
loadNotifications();
await loadBatchesAndRespondents();
initModal();
document.getElementById('loading-overlay').classList.add('hidden');
} catch (e) {
console.error('Init error:', e);
window.location.href = '/dash/login';
}
}
function updateHeader() {
const d = (currentCompany.monthly_credits - currentCompany.monthly_credits_used) + currentCompany.extra_credits;
document.getElementById('credits-total').textContent = d;
document.getElementById('user-name').textContent = currentCompany.name;
const btn = document.getElementById('btn-diagnostico-completo');
if (currentCompany.diagnostico_url) {
btn.href = currentCompany.diagnostico_url;
btn.style.display = 'inline-flex';
} else {
btn.style.display = 'none';
}
}
// ========== NOTIFICATIONS ==========
async function loadNotifications() {
const { data: n, error } = await supabaseClient
.from('notifications')
.select('*')
.eq('company_id', currentCompany.id)
.order('created_at', { ascending: false })
.limit(20);
if (error) return;
const uc = n.filter(x => !x.read).length;
const b = document.getElementById('notification-badge');
b.textContent = uc;
b.classList.toggle('show', uc > 0);
const l = document.getElementById('notifications-list');
if (n.length === 0) {
l.innerHTML = '
';
return;
}
l.innerHTML = n.map(x => `
${x.title}
${x.message || ''}
`).join('');
}
// ========== BATCHES & RESPONDENTS ==========
async function loadBatchesAndRespondents() {
const { data: batchesData, error: batchError } = await supabaseClient
.from('diagnosis_batches')
.select('*')
.eq('company_id', currentCompany.id)
.order('diagnosis_date', { ascending: false });
if (batchError) {
console.error('Erro ao carregar batches:', batchError);
batches = [];
} else {
batches = batchesData || [];
}
const { data: resp, error: respError } = await supabaseClient
.from('respondents')
.select('*')
.eq('company_id', currentCompany.id)
.order('completed_at', { ascending: false });
if (respError) {
console.error('Erro ao carregar respondentes:', respError);
return;
}
const individuais = resp.filter(r => r.main_style && !r.batch_id);
const semBatch = resp.filter(r => !r.main_style && !r.batch_id);
const comBatch = resp.filter(r => r.batch_id);
batchData = {};
batches.forEach(batch => {
batchData[batch.id] = {
id: batch.id,
label: batch.label,
color: batch.color || '#3B82F6',
type: batch.type,
puras: [],
aspiracionais: []
};
if (!activeBatches[batch.id]) {
activeBatches[batch.id] = {
visible: true,
showAs: true,
showCluster: true
};
}
});
comBatch.forEach(r => {
if (!r.coord_flexible || !batchData[r.batch_id]) return;
const coord = {
f: r.coord_flexible,
e: r.coord_stable,
c: r.coord_independent,
a: r.coord_interdependent
};
if (r.label && r.label.startsWith('as-')) {
batchData[r.batch_id].aspiracionais.push(coord);
} else {
batchData[r.batch_id].puras.push(coord);
}
});
renderRespondentsList(individuais);
const pontos = [];
uniqueLabelsMap = generateUniqueLabels(individuais);
individuais.forEach(r => {
if (r.coord_flexible != null) {
const lb = uniqueLabelsMap[r.id] || { shortLabel: r.name.split(' ')[0] };
pontos.push({
f: r.coord_flexible,
e: r.coord_stable,
c: r.coord_independent,
a: r.coord_interdependent,
id: r.id,
shortLabel: lb.shortLabel,
tipo: 'individual'
});
}
});
semBatch.forEach(r => {
if (r.coord_flexible != null) {
pontos.push({
f: r.coord_flexible,
e: r.coord_stable,
c: r.coord_independent,
a: r.coord_interdependent,
tipo: 'semBatch'
});
}
});
drawMatriz(pontos);
}
function renderRespondentsList(individuais) {
const list = document.getElementById('respondentes-list');
document.getElementById('respondentes-count').textContent = `${individuais.length} pessoa${individuais.length !== 1 ? 's' : ''}`;
if (individuais.length === 0) {
list.innerHTML = `
Nenhum respondente ainda.
Gere um link para começar.
`;
return;
}
list.innerHTML = individuais.map(r => {
const lb = uniqueLabelsMap[r.id] || { shortLabel: r.name.split(' ')[0] };
const ia = activeLabels[r.id] !== false;
const co = getColorForLabel(r.id);
const rl = r.report_url || `/dash/relatorio/${r.id}`;
const ie = r.report_url && r.report_url.startsWith('http');
return `
${r.name}
${r.assessment_type === 'qore_scan' ? 'Qore Scan' : r.assessment_type === 'manual' ? 'Manual' : 'Quick Scan'} • ${formatDate(r.completed_at)}
${r.main_style}
`;
}).join('');
}
// ========== MATRIZ ==========
function drawMatriz(pontos) {
const w = MATRIZ_SIZE, h = MATRIZ_SIZE;
d3.select('#matrix').html('');
const svg = d3.select('#matrix').append('svg')
.attr('width', '100%')
.attr('height', '100%')
.attr('viewBox', `0 0 ${w} ${h}`);
matrizData = pontos.map(p => {
const pos = calcularPosicaoSVG(p.f, p.e, p.c, p.a);
return { ...p, svgX: pos.svgX, svgY: pos.svgY };
});
const semBatch = matrizData.filter(d => d.tipo === 'semBatch');
const opSemBatch = semBatch.length > 100 ? 0.08 : semBatch.length > 50 ? 0.12 : 0.2;
semBatch.forEach(d => {
svg.append('circle')
.attr('cx', d.svgX)
.attr('cy', d.svgY)
.attr('r', RAIO_PONTO)
.attr('fill', '#FFFFFF')
.attr('opacity', opSemBatch);
});
Object.keys(batchData).forEach(batchId => {
const batch = batchData[batchId];
const state = activeBatches[batchId];
if (!state || !state.visible) return;
const opPuras = batch.puras.length > 100 ? 0.15 : batch.puras.length > 50 ? 0.25 : 0.4;
batch.puras.forEach(coord => {
const pos = calcularPosicaoSVG(coord.f, coord.e, coord.c, coord.a);
svg.append('circle')
.attr('cx', pos.svgX)
.attr('cy', pos.svgY)
.attr('r', RAIO_PONTO)
.attr('fill', batch.color)
.attr('opacity', opPuras);
});
if (state.showAs && batch.aspiracionais.length > 0) {
batch.aspiracionais.forEach(coord => {
const pos = calcularPosicaoSVG(coord.f, coord.e, coord.c, coord.a);
svg.append('circle')
.attr('cx', pos.svgX)
.attr('cy', pos.svgY)
.attr('r', RAIO_PONTO)
.attr('fill', '#ea3659')
.attr('opacity', 0.4);
});
}
if (state.showCluster && batch.puras.length >= MIN_COORDS_FOR_CLUSTER) {
const pontosPG = batch.puras.map(p => ({
x: parseFloat(p.a) || 0,
y: parseFloat(p.e) || 0
}));
drawPGForBatch(svg, pontosPG, batch.label, batch.color);
}
if (state.showAs && state.showCluster && batch.aspiracionais.length >= MIN_COORDS_FOR_CLUSTER) {
const pontosAS = batch.aspiracionais.map(p => ({
x: parseFloat(p.a) || 0,
y: parseFloat(p.e) || 0
}));
drawPGForBatch(svg, pontosAS, batch.label + 'ₐ', '#ea3659');
}
});
const individuais = matrizData.filter(d => d.tipo === 'individual');
individuais.forEach(d => {
if (!activeLabels.hasOwnProperty(d.id)) activeLabels[d.id] = true;
if (activeLabels[d.id] === false) return;
const co = getColorForLabel(d.id);
svg.append('circle')
.attr('cx', d.svgX)
.attr('cy', d.svgY)
.attr('r', RAIO_PONTO)
.attr('fill', co)
.attr('opacity', 0.7);
svg.append('text')
.attr('x', d.svgX)
.attr('y', d.svgY + 4)
.attr('fill', 'white')
.attr('font-size', '10px')
.attr('text-anchor', 'middle')
.text(d.shortLabel);
});
drawStruct(svg, w, h);
updateBatchControls();
}
function drawPGForBatch(svg, pontos, label, color) {
if (pontos.length < 3) return;
const cl = kMeansClusterizacao(pontos, NUM_CLUSTERS_PG);
const cu = unificarClustersProximos(cl);
let cv = cu
.filter(c => c.densidade / pontos.length >= MIN_PERCENTUAL_CLUSTER)
.sort((a, b) => b.densidade - a.densidade);
if (cv.length === 0) return;
const c = cv[0];
const pos = calcularPosicaoSVG(100 - c.centro.y, c.centro.y, 100 - c.centro.x, c.centro.x);
animRadar(svg, pos.svgX, pos.svgY, RAIO_PG, color);
svg.append('circle')
.attr('cx', pos.svgX)
.attr('cy', pos.svgY)
.attr('r', RAIO_PG)
.attr('fill', color)
.attr('opacity', 0.3);
const shortLabel = label.length > 8 ? label.substring(0, 8) : label;
svg.append('text')
.attr('x', pos.svgX)
.attr('y', pos.svgY + 5)
.attr('fill', 'white')
.attr('font-size', '10px')
.attr('font-weight', 'bold')
.attr('text-anchor', 'middle')
.text(shortLabel);
}
function drawStruct(svg, w, h) {
const dg = 'white', lg = '#A781F3', cx = w / 2, cy = h / 2;
svg.append('line').attr('x1', cx).attr('y1', 0).attr('x2', cx).attr('y2', h).attr('stroke', dg).attr('stroke-width', 1);
svg.append('line').attr('x1', 0).attr('y1', cy).attr('x2', w).attr('y2', cy).attr('stroke', dg).attr('stroke-width', 1);
svg.append('line').attr('x1', 0).attr('y1', 0).attr('x2', w).attr('y2', h).attr('stroke', lg).attr('stroke-width', 1).attr('stroke-dasharray', '5,5');
svg.append('line').attr('x1', w).attr('y1', 0).attr('x2', 0).attr('y2', h).attr('stroke', lg).attr('stroke-width', 1).attr('stroke-dasharray', '5,5');
[1, 2, 3].forEach(i => {
const o = w / 6 * i;
svg.append('rect')
.attr('x', o).attr('y', o)
.attr('width', w - 2 * o).attr('height', h - 2 * o)
.attr('stroke', lg).attr('stroke-width', 1)
.attr('stroke-dasharray', '5,5').attr('fill', 'none');
});
const ql = [
{ x: w * 0.15, y: h * 0.3, t: 'APRENDIZADO' },
{ x: w * 0.35, y: h * 0.08, t: 'PRAZER' },
{ x: w * 0.65, y: h * 0.08, t: 'PROPÓSITO' },
{ x: w * 0.85, y: h * 0.3, t: 'ACOLHIMENTO' },
{ x: w * 0.85, y: h * 0.72, t: 'ORDEM' },
{ x: w * 0.65, y: h * 0.92, t: 'SEGURANÇA' },
{ x: w * 0.35, y: h * 0.92, t: 'AUTORIDADE' },
{ x: w * 0.15, y: h * 0.72, t: 'RESULTADO' }
];
ql.forEach(l => svg.append('text')
.attr('x', l.x).attr('y', l.y)
.attr('fill', 'white').attr('font-size', '9px')
.attr('text-anchor', 'middle').attr('opacity', 0.6)
.text(l.t));
}
function animRadar(svg, x, y, r, co) {
for (let i = 0; i < 3; i++) {
const c = svg.append('circle')
.attr('cx', x).attr('cy', y).attr('r', r)
.attr('fill', co).attr('opacity', 0);
(function rp() {
c.attr('r', r).attr('opacity', 0)
.transition().duration(1000).attr('r', r * 3).attr('opacity', 0.1)
.transition().duration(1000).attr('r', r * 6).attr('opacity', 0)
.on('end', rp);
})();
}
for (let i = 0; i < 3; i++) {
const c = svg.append('circle')
.attr('cx', x).attr('cy', y).attr('r', r)
.attr('fill', 'none').attr('stroke', co)
.attr('stroke-width', 2).attr('opacity', 0.05);
(function rp() {
c.transition().duration(2000).attr('r', r * 4).attr('opacity', 0)
.transition().duration(0).attr('r', r).attr('opacity', 0.15)
.on('end', rp);
})();
}
}
// ========== BATCH CONTROLS ==========
function updateBatchControls() {
const controlsContainer = document.getElementById('matriz-controls');
controlsContainer.innerHTML = '';
if (batches.length === 0) return;
const mainContainer = document.createElement('div');
mainContainer.style.cssText = 'display: flex; flex-direction: column; gap: 12px; width: 100%;';
const activeControlsDiv = document.createElement('div');
activeControlsDiv.className = 'batch-active-controls';
activeControlsDiv.style.cssText = 'display: flex; flex-direction: column; gap: 8px;';
const availableBatchesDiv = document.createElement('div');
availableBatchesDiv.className = 'batch-available';
availableBatchesDiv.style.cssText = 'display: flex; flex-wrap: wrap; gap: 8px; justify-content: center;';
batches.forEach(batch => {
const data = batchData[batch.id];
const state = activeBatches[batch.id] || { visible: false, showAs: true, showCluster: true };
const hasAs = data && data.aspiracionais.length > 0;
const hasCluster = data && data.puras.length >= MIN_COORDS_FOR_CLUSTER;
const batchBtn = document.createElement('button');
batchBtn.className = `batch-toggle-btn ${state.visible ? 'active' : ''}`;
batchBtn.style.cssText = `
display: inline-flex; align-items: center; gap: 6px;
padding: 6px 12px; border-radius: 20px;
background: ${state.visible ? 'rgba(255,255,255,0.15)' : 'rgba(255,255,255,0.05)'};
border: 2px solid ${state.visible ? batch.color : 'rgba(255,255,255,0.2)'};
color: ${state.visible ? '#fff' : 'rgba(255,255,255,0.5)'};
font-size: 12px; font-weight: 500;
cursor: pointer; transition: all 0.2s;
`;
batchBtn.innerHTML = `
${batch.label}
(${data ? data.puras.length : 0})
`;
batchBtn.onclick = () => toggleBatchVisibility(batch.id);
availableBatchesDiv.appendChild(batchBtn);
if (state.visible && (hasAs || hasCluster)) {
const controlRow = document.createElement('div');
controlRow.className = 'batch-control-row';
controlRow.style.cssText = `
display: flex; align-items: center; gap: 8px;
padding: 6px 12px; border-radius: 8px;
background: rgba(255,255,255,0.05);
border-left: 3px solid ${batch.color};
`;
const labelSpan = document.createElement('span');
labelSpan.style.cssText = `font-size: 12px; color: ${batch.color}; font-weight: 500; min-width: 80px;`;
labelSpan.textContent = batch.label;
controlRow.appendChild(labelSpan);
if (hasAs) {
const asBtn = document.createElement('button');
asBtn.className = `control-toggle ${state.showAs ? 'active' : ''}`;
asBtn.style.cssText = `
padding: 4px 8px; border-radius: 4px; font-size: 11px;
background: ${state.showAs ? 'rgba(234, 54, 89, 0.3)' : 'rgba(255,255,255,0.1)'};
border: 1px solid ${state.showAs ? '#ea3659' : 'rgba(255,255,255,0.2)'};
color: ${state.showAs ? '#ea3659' : 'rgba(255,255,255,0.5)'};
cursor: pointer;
`;
asBtn.textContent = `as (${data.aspiracionais.length})`;
asBtn.onclick = (e) => { e.stopPropagation(); toggleBatchAs(batch.id); };
controlRow.appendChild(asBtn);
}
if (hasCluster) {
const clusterBtn = document.createElement('button');
clusterBtn.className = `control-toggle ${state.showCluster ? 'active' : ''}`;
clusterBtn.style.cssText = `
padding: 4px 8px; border-radius: 4px; font-size: 11px;
background: ${state.showCluster ? `${batch.color}33` : 'rgba(255,255,255,0.1)'};
border: 1px solid ${state.showCluster ? batch.color : 'rgba(255,255,255,0.2)'};
color: ${state.showCluster ? batch.color : 'rgba(255,255,255,0.5)'};
cursor: pointer;
`;
clusterBtn.textContent = 'pG';
clusterBtn.onclick = (e) => { e.stopPropagation(); toggleBatchCluster(batch.id); };
controlRow.appendChild(clusterBtn);
}
activeControlsDiv.appendChild(controlRow);
}
});
if (activeControlsDiv.children.length > 0) {
mainContainer.appendChild(activeControlsDiv);
}
mainContainer.appendChild(availableBatchesDiv);
controlsContainer.appendChild(mainContainer);
}
function toggleBatchVisibility(batchId) {
if (!activeBatches[batchId]) {
activeBatches[batchId] = { visible: true, showAs: true, showCluster: true };
} else {
activeBatches[batchId].visible = !activeBatches[batchId].visible;
}
redrawMatriz();
}
function toggleBatchAs(batchId) {
if (activeBatches[batchId]) {
activeBatches[batchId].showAs = !activeBatches[batchId].showAs;
}
redrawMatriz();
}
function toggleBatchCluster(batchId) {
if (activeBatches[batchId]) {
activeBatches[batchId].showCluster = !activeBatches[batchId].showCluster;
}
redrawMatriz();
}
function toggleRespondentLabel(id) {
activeLabels[id] = activeLabels[id] === false ? true : false;
const ia = activeLabels[id] !== false;
const co = getColorForLabel(id);
document.querySelectorAll(`.respondente-style[data-id="${id}"]`).forEach(b => {
b.classList.toggle('inactive', !ia);
b.style.background = ia ? co : 'rgba(255,255,255,0.1)';
b.style.color = ia ? '#fff' : 'rgba(255,255,255,0.4)';
});
redrawMatriz();
}
function redrawMatriz() {
if (matrizData.length === 0 && Object.keys(batchData).length === 0) {
drawMatriz([]);
return;
}
drawMatriz(matrizData);
}
// ========== MODAL LOGIC ==========
function initModal() {
const ta = document.getElementById('toggle-amostra');
const ac = document.getElementById('amostra-config');
const cc = document.getElementById('config-completo');
const s2 = document.getElementById('diag-step-2');
ta.addEventListener('click', () => {
amostraAtiva = !amostraAtiva;
ta.classList.toggle('active', amostraAtiva);
ac.style.display = amostraAtiva ? 'block' : 'none';
recalc();
});
document.querySelectorAll('input[name="diag-type"]').forEach(r => r.addEventListener('change', e => {
tipoSelecionado = e.target.value;
document.querySelectorAll('.radio-option[data-type]').forEach(o => o.classList.remove('selected'));
e.target.closest('.radio-option').classList.add('selected');
cc.style.display = tipoSelecionado === 'completo' ? 'block' : 'none';
s2.classList.remove('hidden');
recalc();
}));
['diag-populacao', 'diag-confianca', 'diag-erro', 'diag-recortes', 'diag-perguntas'].forEach(id => {
const el = document.getElementById(id);
if (el) {
el.addEventListener('input', recalc);
el.addEventListener('change', recalc);
}
});
}
function recalc() {
const pop = parseInt(document.getElementById('diag-populacao').value) || 0;
const conf = parseInt(document.getElementById('diag-confianca').value) || 95;
const err = parseInt(document.getElementById('diag-erro').value) || 2;
const rec = parseInt(document.getElementById('diag-recortes').value) || 2;
const per = parseInt(document.getElementById('diag-perguntas').value) || 0;
let resp = pop;
if (amostraAtiva && pop > 0) {
resp = calcularAmostra(pop, conf, err);
document.getElementById('amostra-resultado').textContent = resp;
document.getElementById('amostra-detail').textContent = `${conf}% de confiança, ${err}% de margem de erro`;
} else if (!amostraAtiva && pop > 0) {
document.getElementById('amostra-resultado').textContent = pop;
document.getElementById('amostra-detail').textContent = 'Censo completo (100% dos colaboradores)';
} else {
document.getElementById('amostra-resultado').textContent = '--';
document.getElementById('amostra-detail').textContent = 'Preencha a quantidade de colaboradores';
}
let preco = 0;
if (resp > 0 && tipoSelecionado) {
preco = tipoSelecionado === 'completo' ? calcularPrecoCompleto(resp, rec, per) : calcularPrecoPulso(resp);
}
document.getElementById('preco-resultado').textContent = preco.toLocaleString('pt-BR');
document.getElementById('btn-solicitar-orcamento').disabled = preco === 0 || !tipoSelecionado;
}
function resetModal() {
document.getElementById('diag-populacao').value = '';
document.getElementById('diag-step-2').classList.add('hidden');
document.querySelectorAll('input[name="diag-type"]').forEach(r => r.checked = false);
document.querySelectorAll('.radio-option[data-type]').forEach(o => o.classList.remove('selected'));
tipoSelecionado = null;
amostraAtiva = true;
document.getElementById('toggle-amostra').classList.add('active');
document.getElementById('amostra-config').style.display = 'block';
document.getElementById('config-completo').style.display = 'block';
document.getElementById('diag-form-content').classList.remove('hidden');
document.getElementById('diag-success').classList.add('hidden');
document.getElementById('diag-footer').style.display = 'flex';
recalc();
}
// ========== EVENT LISTENERS ==========
document.getElementById('btn-novo-diagnostico').addEventListener('click', () => {
resetModal();
openModal('modal-novo-diagnostico');
});
document.getElementById('btn-solicitar-orcamento').addEventListener('click', async () => {
const btn = document.getElementById('btn-solicitar-orcamento');
btn.disabled = true;
btn.textContent = 'Enviando...';
const pop = parseInt(document.getElementById('diag-populacao').value) || 0;
const conf = parseInt(document.getElementById('diag-confianca').value) || 95;
const err = parseInt(document.getElementById('diag-erro').value) || 2;
const rec = parseInt(document.getElementById('diag-recortes').value) || 2;
const per = parseInt(document.getElementById('diag-perguntas').value) || 0;
const resp = amostraAtiva ? calcularAmostra(pop, conf, err) : pop;
const preco = tipoSelecionado === 'completo' ? calcularPrecoCompleto(resp, rec, per) : calcularPrecoPulso(resp);
const tn = tipoSelecionado === 'completo' ? 'Diagnóstico Completo' : 'Pulso Rápido';
try {
const { data: qd, error: qe } = await supabaseClient.from('quote_requests').insert({
company_id: currentCompany.id,
tipo: tipoSelecionado,
populacao: pop,
respondentes: resp,
amostra: amostraAtiva,
confianca: amostraAtiva ? conf : null,
erro: amostraAtiva ? err : null,
recortes: tipoSelecionado === 'completo' ? rec : null,
perguntas: tipoSelecionado === 'completo' ? per : null,
preco_estimado: preco
}).select().single();
if (qe) throw qe;
await supabaseClient.from('notifications').insert({
company_id: currentCompany.id,
title: '📋 Orçamento solicitado',
message: `Seu pedido de ${tn} (R$ ${preco.toLocaleString('pt-BR')}) foi recebido. Em breve entraremos em contato.`,
type: 'quote',
reference_id: qd.id,
read: false
});
await supabaseClient.from('admin_alerts').insert({
type: 'quote_request',
title: `Novo orçamento: ${currentCompany.name}`,
message: `${tn} • ${resp} respondentes • R$ ${preco.toLocaleString('pt-BR')}`,
reference_id: qd.id,
company_id: currentCompany.id
});
document.getElementById('diag-form-content').classList.add('hidden');
document.getElementById('diag-success').classList.remove('hidden');
document.getElementById('diag-footer').style.display = 'none';
loadNotifications();
} catch (e) {
console.error(e);
alert('Erro ao enviar orçamento.');
btn.disabled = false;
btn.textContent = 'Solicitar Orçamento';
}
});
document.getElementById('btn-gerar-link').addEventListener('click', () => {
document.getElementById('link-result').style.display = 'none';
document.getElementById('btn-confirmar-link').style.display = 'inline-flex';
document.getElementById('btn-confirmar-link').disabled = false;
document.getElementById('btn-confirmar-link').textContent = 'Gerar Link';
openModal('modal-gerar-link');
});
document.getElementById('btn-confirmar-link').addEventListener('click', async () => {
const t = document.querySelector('input[name="assessment-type"]:checked').value;
const btn = document.getElementById('btn-confirmar-link');
btn.disabled = true;
btn.textContent = 'Gerando...';
try {
const { data, error } = await supabaseClient.rpc('create_assessment_link', {
p_assessment_type: t,
p_max_responses: t === 'quick_scan' ? 10 : 1
});
if (error) throw error;
if (!data.success) throw new Error(data.error);
document.getElementById('generated-link').value = data.url;
document.getElementById('link-result').style.display = 'block';
btn.style.display = 'none';
const { data: cd } = await supabaseClient.rpc('get_current_company');
if (cd.success) {
currentCompany = cd.company;
updateHeader();
}
loadNotifications();
} catch (e) {
alert(e.message || 'Erro ao gerar link');
btn.disabled = false;
btn.textContent = 'Gerar Link';
}
});
function copyLink() {
const i = document.getElementById('generated-link');
i.select();
document.execCommand('copy');
event.target.textContent = 'Copiado!';
setTimeout(() => event.target.textContent = 'Copiar', 2000);
}
document.getElementById('btn-autodiagnostico').addEventListener('click', () => window.location.href = '/dash/autodiagnostico');
document.getElementById('notification-btn').addEventListener('click', () => openModal('modal-notificacoes'));
document.getElementById('mark-all-read').addEventListener('click', async () => {
await supabaseClient.from('notifications').update({ read: true }).eq('company_id', currentCompany.id);
loadNotifications();
});
document.getElementById('clear-read').addEventListener('click', async () => {
await supabaseClient.from('notifications').delete().eq('company_id', currentCompany.id).eq('read', true);
loadNotifications();
});
function openModal(id) { document.getElementById(id).classList.add('show'); }
function closeModal(id) { document.getElementById(id).classList.remove('show'); }
function formatDate(ds) { return new Date(ds).toLocaleDateString('pt-BR', { day: '2-digit', month: '2-digit', year: 'numeric' }); }
// ========== INIT ==========
initDash();