Transforme dados brutos em
Oportunidades de Venda
Filtre automaticamente negócios sem website, organize por nicho e exporte para prospecção em massa.
Carregando dashboard...
import React, { useState, lazy, Suspense } from 'react'; import Papa from 'papaparse'; import FileUpload from './components/FileUpload'; import { Layers, AlertCircle, X } from 'lucide-react'; // Lazy load Dashboard since it's not needed on initial load const Dashboard = lazy(() => import('./components/Dashboard')); function App() { const [view, setView] = useState('upload'); // 'upload' | 'dashboard' const [rawData, setRawData] = useState([]); const [processedData, setProcessedData] = useState({}); const [stats, setStats] = useState({ total: 0, noWebsite: 0, niches: 0 }); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [showExportModal, setShowExportModal] = useState(false); const [selectedNiches, setSelectedNiches] = useState([]); const handleFileUpload = (files) => { // Reset states setError(null); setLoading(true); // Validate files const MAX_FILE_SIZE = 50 * 1024 * 1024; // 50MB for (const file of files) { if (!file.name.endsWith('.csv')) { setError('Por favor, selecione apenas arquivos CSV.'); setLoading(false); return; } if (file.size > MAX_FILE_SIZE) { setError(`O arquivo ${file.name} é muito grande. Tamanho máximo: 50MB.`); setLoading(false); return; } } const parsePromises = files.map(file => { return new Promise((resolve, reject) => { Papa.parse(file, { header: true, skipEmptyLines: true, // REMOVED worker: true - causes issues in production/Hugging Face complete: (results) => { if (results.errors && results.errors.length > 0) { console.warn('CSV parsing warnings:', results.errors); } resolve(results.data); }, error: (error) => { console.error("Error parsing CSV:", error); reject(error); } }); }); }); Promise.all(parsePromises) .then(resultsArray => { // Flatten array of arrays const allData = resultsArray.flat(); if (allData.length === 0) { setError('Nenhum dado encontrado nos arquivos CSV.'); setLoading(false); return; } processData(allData); setLoading(false); }) .catch(error => { console.error("Error processing files:", error); setError(`Erro ao processar arquivos: ${error.message || 'Erro desconhecido'}`); setLoading(false); }); }; const processData = (data) => { setRawData(data); // Filter: Keep only those WITHOUT a website AND WITH a phone number const filteredData = data.filter(item => { const hasNoWebsite = !item.website || item.website.trim() === ''; const hasPhone = item.phone && item.phone.trim() !== ''; return hasNoWebsite && hasPhone; }).map((item, index) => ({ ...item, // Generate a unique ID based on content or fallback to index if needed id: `${item.title || 'unknown'}-${item.phone || 'no-phone'}-${index}` })); // Group by Niche (categoryName) const grouped = {}; filteredData.forEach(item => { // Normalize category name const niche = item.categoryName ? item.categoryName.trim() : 'Outros'; if (!grouped[niche]) { grouped[niche] = []; } grouped[niche].push(item); }); setProcessedData(grouped); setStats({ total: data.length, noWebsite: filteredData.length, niches: Object.keys(grouped).length }); setView('dashboard'); }; const openExportModal = () => { // Initialize with all niches selected setSelectedNiches(Object.keys(processedData)); setShowExportModal(true); }; const toggleNicheSelection = (niche) => { setSelectedNiches(prev => { if (prev.includes(niche)) { return prev.filter(n => n !== niche); } else { return [...prev, niche]; } }); }; const toggleSelectAll = () => { if (selectedNiches.length === Object.keys(processedData).length) { setSelectedNiches([]); } else { setSelectedNiches(Object.keys(processedData)); } }; const handleExport = () => { if (selectedNiches.length === 0) { setError('Por favor, selecione pelo menos um nicho para exportar.'); return; } // Flatten the grouped data back to a list for export // Only include selected niches const exportList = []; selectedNiches.forEach(niche => { const items = processedData[niche] || []; items.forEach(item => { exportList.push({ Name: item.title, Phone: item.phone, Address: `${item.street || ''} ${item.city || ''} ${item.state || ''}`.trim(), Niche: niche }); }); }); const csv = Papa.unparse(exportList); const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' }); const url = URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; // Generate filename with selected niches info const filename = selectedNiches.length === Object.keys(processedData).length ? 'leads_todos_nichos.csv' : selectedNiches.length === 1 ? `leads_${selectedNiches[0].toLowerCase().replace(/[^a-z0-9]/g, '_')}.csv` : `leads_${selectedNiches.length}_nichos.csv`; link.setAttribute('download', filename); document.body.appendChild(link); link.click(); document.body.removeChild(link); setShowExportModal(false); }; return (
Filtre automaticamente negócios sem website, organize por nicho e exporte para prospecção em massa.
Carregando dashboard...
Selecione os nichos que deseja exportar