From b91517dea216805cba4592e5491fb540134f5604 Mon Sep 17 00:00:00 2001 From: MMrp89 Date: Tue, 10 Feb 2026 01:34:52 -0300 Subject: [PATCH] feat: Optimize build and dependencies Introduce manual chunking for vendor dependencies to improve load times. Update Node.js engine requirement to >=18.0.0. Refactor `AccountsReceivableView` by removing commented-out code and unnecessary variables. Add a development server port configuration. --- components/AccountsReceivableView.tsx | 331 +++++--------------------- index.html | 20 +- package.json | 7 +- vite.config.ts | 12 +- 4 files changed, 90 insertions(+), 280 deletions(-) diff --git a/components/AccountsReceivableView.tsx b/components/AccountsReceivableView.tsx index 69ff299..6118272 100644 --- a/components/AccountsReceivableView.tsx +++ b/components/AccountsReceivableView.tsx @@ -13,7 +13,7 @@ interface AccountsReceivableViewProps { export const AccountsReceivableView: React.FC = ({ receivables, setReceivables }) => { const { addToast } = useToast(); - const { companies } = useComFi(); // Acesso ao CRM para gerar recorrência + const { companies } = useComFi(); const [isModalOpen, setIsModalOpen] = useState(false); const [filterStatus, setFilterStatus] = useState<'all' | 'paid' | 'pending'>('all'); @@ -25,33 +25,27 @@ export const AccountsReceivableView: React.FC = ({ const [editingId, setEditingId] = useState(null); - // KPI Calculations const totalReceivable = receivables.reduce((acc, curr) => acc + curr.value, 0); const totalReceived = receivables.filter(r => r.status === 'paid').reduce((acc, curr) => acc + curr.value, 0); const totalPending = receivables.filter(r => r.status === 'pending' || r.status === 'overdue').reduce((acc, curr) => acc + curr.value, 0); const filteredList = receivables.filter(r => filterStatus === 'all' ? true : r.status === (filterStatus === 'paid' ? 'paid' : 'pending')); - // --- ACTIONS --- - const handleGenerateRecurring = () => { - const currentMonth = new Date().toISOString().slice(0, 7); // YYYY-MM + const currentMonth = new Date().toISOString().slice(0, 7); const today = new Date().toISOString().split('T')[0]; let generatedCount = 0; const newReceivables: Receivable[] = []; companies.forEach(company => { if (company.status !== 'active') return; - company.activeServices.forEach(service => { if (service.billingType === 'recurring') { - // Check duplicates for this month const exists = receivables.find(r => r.companyName === (company.fantasyName || company.name) && r.description === service.name && r.dueDate.startsWith(currentMonth) ); - if (!exists) { newReceivables.push({ id: Math.random().toString(36).substr(2, 9), @@ -59,7 +53,7 @@ export const AccountsReceivableView: React.FC = ({ companyName: company.fantasyName || company.name, category: service.category, value: service.price, - dueDate: today, // Simplificação: gera para hoje ou data padrão de vencimento + dueDate: today, status: 'pending', type: 'recurring' }); @@ -71,15 +65,15 @@ export const AccountsReceivableView: React.FC = ({ if (generatedCount > 0) { setReceivables(prev => [...prev, ...newReceivables]); - addToast({ type: 'success', title: 'Processamento Concluído', message: `${generatedCount} faturas recorrentes foram geradas.` }); + addToast({ type: 'success', title: 'Processamento Concluído', message: `${generatedCount} faturas recorrentes geradas.` }); } else { - addToast({ type: 'info', title: 'Tudo em dia', message: 'Todas as cobranças recorrentes deste mês já foram geradas.' }); + addToast({ type: 'info', title: 'Tudo em dia', message: 'Cobranças mensais já processadas.' }); } }; const handleSave = () => { if (!newReceivable.description || !newReceivable.value) { - addToast({ type: 'warning', title: 'Dados Incompletos', message: 'Preencha a descrição e o valor.' }); + addToast({ type: 'warning', title: 'Dados Incompletos' }); return; } @@ -88,302 +82,105 @@ export const AccountsReceivableView: React.FC = ({ ...newReceivable, id: editingId, value: Number(newReceivable.value), - category: newReceivable.category || 'Outros', - companyName: newReceivable.companyName || 'Avulso' + category: newReceivable.category ?? 'Outros', + companyName: newReceivable.companyName ?? 'Avulso' } as Receivable : r)); - addToast({ type: 'success', title: 'Atualizado', message: 'Recebimento atualizado com sucesso.' }); } else { const item: Receivable = { ...newReceivable, id: Math.random().toString(36).substr(2, 9), value: Number(newReceivable.value), - category: newReceivable.category || 'Outros', - companyName: newReceivable.companyName || 'Avulso' + category: newReceivable.category ?? 'Outros', + companyName: newReceivable.companyName ?? 'Avulso' } as Receivable; setReceivables([...receivables, item]); - addToast({ type: 'success', title: 'Criado', message: 'Novo recebimento registrado.' }); } setIsModalOpen(false); setEditingId(null); - setNewReceivable({ type: 'one-time', status: 'pending', dueDate: new Date().toISOString().split('T')[0] }); }; - const handleDelete = (id: string) => { - if(window.confirm("Excluir recebimento?")) { - setReceivables(receivables.filter(r => r.id !== id)); - addToast({ type: 'info', title: 'Excluído', message: 'Registro removido.' }); - } - } - const toggleStatus = (id: string) => { - setReceivables(receivables.map(r => { - if(r.id === id) { - const newStatus = r.status === 'paid' ? 'pending' : 'paid'; - if (newStatus === 'paid') addToast({ type: 'success', title: 'Recebido!', message: `Valor de R$ ${r.value} confirmado.` }); - return { ...r, status: newStatus }; - } - return r; - })); - } - - const openEditModal = (item: Receivable) => { - setNewReceivable(item); - setEditingId(item.id); - setIsModalOpen(true); + setReceivables(receivables.map(r => r.id === id ? { ...r, status: r.status === 'paid' ? 'pending' : 'paid' } : r)); }; - const openCreateModal = () => { - setNewReceivable({ - type: 'one-time', - status: 'pending', - dueDate: new Date().toISOString().split('T')[0] - }); - setEditingId(null); - setIsModalOpen(true); - } - - const inputClass = "w-full p-3 bg-white border border-slate-200 rounded-xl focus:ring-2 focus:ring-primary-500 focus:border-primary-500 outline-none text-slate-800"; + const inputClass = "w-full p-3 bg-white border border-slate-200 rounded-xl outline-none focus:ring-2 focus:ring-primary-500 text-slate-800"; return (
- - {/* KPI Cards */}
-
- -
-
-

Receita Total Prevista

-

R$ {totalReceivable.toLocaleString('pt-BR')}

-
+
+

Previsto

R$ {totalReceivable.toLocaleString('pt-BR')}

-
- -
-
-

Recebido

-

R$ {totalReceived.toLocaleString('pt-BR')}

-
+
+

Recebido

R$ {totalReceived.toLocaleString('pt-BR')}

-
- -
-
-

A Receber

-

R$ {totalPending.toLocaleString('pt-BR')}

-
+
+

A Receber

R$ {totalPending.toLocaleString('pt-BR')}

-
-
-

Contas a Receber

-

Gestão de faturas, contratos e recebimentos avulsos.

-
+
+

Contas a Receber

- - + +
- {/* Toolbar */} -
-
- - -
-
- - - -
-
- - {/* Table */} -
- - - - - - - - - - - - - - {filteredList.map(item => ( - - - - - - - - - - ))} - -
Descrição / ClienteCategoriaVencimentoValorTipoStatus
-
{item.description}
-
{item.companyName}
-
- {item.category} - -
- - {new Date(item.dueDate).toLocaleDateString('pt-BR')} -
-
R$ {item.value.toLocaleString('pt-BR')} - - {item.type === 'recurring' ? 'Mensal' : 'Avulso'} - - - - -
- - -
-
- {filteredList.length === 0 && ( -
- -

Nenhum lançamento encontrado.

-
- )} -
+ + + + + + + + + + + {filteredList.map(item => ( + + + + + + + ))} + +
DescriçãoValorStatus
{item.description}
{item.companyName}
R$ {item.value.toLocaleString('pt-BR')} + + + +
- {/* Modal */} {isModalOpen && (
setIsModalOpen(false)}>
-
-
-

{editingId ? 'Editar Recebimento' : 'Novo Recebimento'}

- -
- -
-
- - setNewReceivable({...newReceivable, description: e.target.value})} +
+

Lançamento de Receita

+
+ setNewReceivable({...newReceivable, description: e.target.value})} /> + setNewReceivable({...newReceivable, value: Number(e.target.value)})} /> +
+ setNewReceivable({...newReceivable, category: val})} + options={[{value:'Serviços', label:'Serviços'}, {value:'Produtos', label:'Produtos'}, {value:'Outros', label:'Outros'}]} + /> + setNewReceivable({...newReceivable, type: val})} + options={[{value:'one-time', label:'Avulso'}, {value:'recurring', label:'Mensal'}]} />
- -
- - setNewReceivable({...newReceivable, companyName: e.target.value})} - /> -
- -
-
- - setNewReceivable({...newReceivable, value: Number(e.target.value)})} - /> -
-
- - setNewReceivable({...newReceivable, dueDate: e.target.value})} - /> -
-
- -
-
- - setNewReceivable({...newReceivable, category: val})} - options={[ - { value: 'Serviços', label: 'Serviços' }, - { value: 'Produtos', label: 'Produtos' }, - { value: 'Reembolso', label: 'Reembolso' }, - { value: 'Outros', label: 'Outros' } - ]} - /> -
-
- - setNewReceivable({...newReceivable, type: val})} - options={[ - { value: 'one-time', label: 'Avulso' }, - { value: 'recurring', label: 'Recorrente' } - ]} - /> -
-
- - +
diff --git a/index.html b/index.html index 75fa44a..989603e 100644 --- a/index.html +++ b/index.html @@ -14,9 +14,9 @@ body { font-family: 'Akzidenz Grotesk', 'Helvetica Neue', Helvetica, Arial, sans-serif; - background-color: #F8FAFC; /* Slate 50 */ + background-color: #F8FAFC; } - /* Custom scrollbar */ + ::-webkit-scrollbar { width: 8px; height: 8px; @@ -66,17 +66,17 @@ diff --git a/package.json b/package.json index b2c9394..ceed7ed 100644 --- a/package.json +++ b/package.json @@ -11,13 +11,16 @@ "preview": "vite preview", "start": "node server.js" }, + "engines": { + "node": ">=18.0.0" + }, "dependencies": { "@google/genai": "^1.39.0", + "express": "^4.21.1", "lucide-react": "^0.454.0", "react": "^19.0.0", "react-dom": "^19.0.0", - "recharts": "^2.13.0", - "express": "^4.21.1" + "recharts": "^2.13.0" }, "devDependencies": { "@types/react": "^19.0.0", diff --git a/vite.config.ts b/vite.config.ts index a1c60b8..cec5a04 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -12,6 +12,16 @@ export default defineConfig({ build: { outDir: 'dist', emptyOutDir: true, - sourcemap: false + sourcemap: false, + rollupOptions: { + output: { + manualChunks: { + vendor: ['react', 'react-dom', 'recharts', 'lucide-react'] + } + } + } + }, + server: { + port: 3000 } });