feat: versão 1.5 - CRM Beta com leads, funis, campanhas e portal do cliente

This commit is contained in:
Erik Silva
2025-12-24 17:36:52 -03:00
parent 99d828869a
commit dfb91c8ba5
98 changed files with 18255 additions and 1465 deletions

View File

@@ -0,0 +1,125 @@
import { NextRequest, NextResponse } from 'next/server';
import { writeFile } from 'fs/promises';
import { join } from 'path';
export async function POST(request: NextRequest) {
try {
const formData = await request.formData();
// Extrair campos do FormData
const personType = formData.get('person_type') as string;
const email = formData.get('email') as string;
const phone = formData.get('phone') as string;
const cpf = formData.get('cpf') as string || '';
const fullName = formData.get('full_name') as string || '';
const cnpj = formData.get('cnpj') as string || '';
const companyName = formData.get('company_name') as string || '';
const tradeName = formData.get('trade_name') as string || '';
const postalCode = formData.get('postal_code') as string || '';
const street = formData.get('street') as string || '';
const number = formData.get('number') as string || '';
const complement = formData.get('complement') as string || '';
const neighborhood = formData.get('neighborhood') as string || '';
const city = formData.get('city') as string || '';
const state = formData.get('state') as string || '';
const message = formData.get('message') as string || '';
const logoFile = formData.get('logo') as File | null;
// Validar campos obrigatórios
if (!email || !phone) {
return NextResponse.json(
{ error: 'E-mail e telefone são obrigatórios' },
{ status: 400 }
);
}
// Validar campos específicos por tipo
if (personType === 'pf') {
if (!cpf || !fullName) {
return NextResponse.json(
{ error: 'CPF e Nome Completo são obrigatórios para Pessoa Física' },
{ status: 400 }
);
}
} else if (personType === 'pj') {
if (!cnpj || !companyName) {
return NextResponse.json(
{ error: 'CNPJ e Razão Social são obrigatórios para Pessoa Jurídica' },
{ status: 400 }
);
}
}
// Processar upload de logo
let logoPath = '';
if (logoFile && logoFile.size > 0) {
try {
const bytes = await logoFile.arrayBuffer();
const buffer = Buffer.from(bytes);
// Criar nome único para o arquivo
const timestamp = Date.now();
const fileExt = logoFile.name.split('.').pop();
const fileName = `logo-${timestamp}.${fileExt}`;
const uploadDir = join(process.cwd(), 'public', 'uploads', 'logos');
logoPath = `/uploads/logos/${fileName}`;
// Salvar arquivo (em produção, use S3, Cloudinary, etc.)
await writeFile(join(uploadDir, fileName), buffer);
} catch (uploadError) {
console.error('Error uploading logo:', uploadError);
// Continuar sem logo em caso de erro
}
}
// Buscar tenant_id do subdomínio (por enquanto hardcoded como 1)
const tenantId = 1;
// Preparar nome baseado no tipo
const customerName = personType === 'pf' ? fullName : (tradeName || companyName);
// Preparar endereço completo
const addressParts = [street, number, complement, neighborhood, city, state, postalCode].filter(Boolean);
const fullAddress = addressParts.join(', ');
// Criar o cliente no backend
const response = await fetch('http://aggios-backend:8080/api/crm/customers', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
tenant_id: tenantId,
name: customerName,
email: email,
phone: phone,
company: personType === 'pj' ? companyName : '',
address: fullAddress,
notes: JSON.stringify({
person_type: personType,
cpf, cnpj, full_name: fullName, company_name: companyName, trade_name: tradeName,
postal_code: postalCode, street, number, complement, neighborhood, city, state,
message, logo_path: logoPath,
}),
status: 'lead',
source: 'cadastro_publico',
}),
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error || 'Erro ao criar cadastro');
}
const data = await response.json();
return NextResponse.json({
message: 'Cadastro realizado com sucesso! Você receberá um e-mail com as credenciais.',
customer_id: data.customer?.id,
});
} catch (error: any) {
console.error('Register error:', error);
return NextResponse.json(
{ error: error.message || 'Erro ao processar cadastro' },
{ status: 500 }
);
}
}