import React, { useState, useRef } from 'react'; import { Proposal, ProposalItem } from '../types'; import { useComFi } from '../contexts/ComFiContext'; import { useToast } from '../contexts/ToastContext'; import { CustomSelect } from './CustomSelect'; import { FileText, Plus, Trash2, Printer, Edit2, CheckCircle2, Send, X, Search, ChevronLeft, Building2, Calendar, DollarSign, Save } from 'lucide-react'; export const ProposalsView: React.FC = () => { const { proposals, setProposals, companies, services, tenant } = useComFi(); const { addToast } = useToast(); const [viewMode, setViewMode] = useState<'list' | 'create' | 'edit'>('list'); const [searchTerm, setSearchTerm] = useState(''); // Form State const [currentProposal, setCurrentProposal] = useState>({ items: [], issueDate: new Date().toISOString().split('T')[0], validUntil: new Date(Date.now() + 15 * 24 * 60 * 60 * 1000).toISOString().split('T')[0], status: 'draft', notes: 'Validade da proposta: 15 dias.\nPagamento: 50% entrada, 50% na entrega.' }); // Items Management const [newItemServiceId, setNewItemServiceId] = useState(''); const calculateTotal = (items: ProposalItem[]) => items.reduce((acc, item) => acc + item.total, 0); const handleAddItem = () => { if (!newItemServiceId) return; const service = services.find(s => s.id === newItemServiceId); if (!service) return; const newItem: ProposalItem = { id: Math.random().toString(36).substr(2, 9), serviceId: service.id, description: service.name, quantity: 1, unitPrice: service.price, total: service.price }; const updatedItems = [...(currentProposal.items || []), newItem]; setCurrentProposal({ ...currentProposal, items: updatedItems, totalValue: calculateTotal(updatedItems) }); setNewItemServiceId(''); }; const handleRemoveItem = (itemId: string) => { const updatedItems = (currentProposal.items || []).filter(i => i.id !== itemId); setCurrentProposal({ ...currentProposal, items: updatedItems, totalValue: calculateTotal(updatedItems) }); }; const handleUpdateItem = (itemId: string, field: 'quantity' | 'unitPrice', value: number) => { const updatedItems = (currentProposal.items || []).map(item => { if (item.id === itemId) { const updatedItem = { ...item, [field]: value }; updatedItem.total = updatedItem.quantity * updatedItem.unitPrice; return updatedItem; } return item; }); setCurrentProposal({ ...currentProposal, items: updatedItems, totalValue: calculateTotal(updatedItems) }); }; const handleSave = () => { if (!currentProposal.clientId || !currentProposal.items?.length) { addToast({ type: 'warning', title: 'Dados Incompletos', message: 'Selecione um cliente e adicione itens.' }); return; } const client = companies.find(c => c.id === currentProposal.clientId); const proposalToSave: Proposal = { ...currentProposal, id: currentProposal.id || Math.random().toString(36).substr(2, 9), number: currentProposal.number || `PROP-${new Date().getFullYear()}-${Math.floor(Math.random() * 1000)}`, clientName: client?.fantasyName || client?.name || 'Cliente', clientEmail: client?.email, totalValue: calculateTotal(currentProposal.items || []) } as Proposal; if (viewMode === 'edit') { setProposals(proposals.map(p => p.id === proposalToSave.id ? proposalToSave : p)); addToast({ type: 'success', title: 'Proposta Atualizada' }); } else { setProposals([...proposals, proposalToSave]); addToast({ type: 'success', title: 'Proposta Criada' }); } setViewMode('list'); }; const handleDelete = (id: string) => { if (window.confirm('Excluir esta proposta?')) { setProposals(proposals.filter(p => p.id !== id)); addToast({ type: 'info', title: 'Proposta Removida' }); } }; const openCreate = () => { setCurrentProposal({ items: [], issueDate: new Date().toISOString().split('T')[0], validUntil: new Date(Date.now() + 15 * 24 * 60 * 60 * 1000).toISOString().split('T')[0], status: 'draft', notes: 'Validade da proposta: 15 dias.\nPagamento: 50% entrada, 50% na entrega.' }); setViewMode('create'); }; const openEdit = (proposal: Proposal) => { setCurrentProposal(proposal); setViewMode('edit'); }; const handlePrint = () => { window.print(); }; // --- RENDER --- if (viewMode === 'create' || viewMode === 'edit') { const client = companies.find(c => c.id === currentProposal.clientId); return (
{/* Print Styles */} {/* Header / Actions */}
{/* Editor Panel (Left) */}

Cliente & Detalhes

setCurrentProposal({...currentProposal, clientId: val})} placeholder="Selecione o Cliente" options={companies.map(c => ({ value: c.id, label: c.fantasyName || c.name }))} />
setCurrentProposal({...currentProposal, issueDate: e.target.value})} />
setCurrentProposal({...currentProposal, validUntil: e.target.value})} />
setCurrentProposal({...currentProposal, status: val})} options={[ { value: 'draft', label: 'Rascunho' }, { value: 'sent', label: 'Enviado' }, { value: 'accepted', label: 'Aceito' }, { value: 'rejected', label: 'Rejeitado' } ]} />

Adicionar Item

({ value: s.id, label: `${s.name} (R$ ${s.price})` }))} />

Notas & Observações

{/* Preview Panel (Right) - The "Paper" */}
{/* Header Documento */}
{tenant.logo ? ( Logo ) : (

{tenant.name}

)}

{tenant.address}

{tenant.email} | {tenant.phone}

Proposta

{currentProposal.number || 'RASCUNHO'}

Data: {new Date(currentProposal.issueDate || '').toLocaleDateString('pt-BR')}

Válido até: {new Date(currentProposal.validUntil || '').toLocaleDateString('pt-BR')}

{/* Info Cliente */}

Preparado para:

{client ? ( <>

{client.fantasyName || client.name}

{client.address} - {client.city}

CNPJ: {client.cnpj}

{client.email}

) : (

Selecione um cliente...

)}
{/* Items Table */}
{(currentProposal.items || []).map((item) => ( ))} {(currentProposal.items || []).length === 0 && ( )}
Descrição / Serviço Qtd Valor Unit. Total
{item.description} handleUpdateItem(item.id, 'quantity', Number(e.target.value))} />
R$ handleUpdateItem(item.id, 'unitPrice', Number(e.target.value))} />
R$ {item.total.toLocaleString('pt-BR', { minimumFractionDigits: 2 })}
Nenhum item adicionado
{/* Totals */}
Subtotal R$ {calculateTotal(currentProposal.items || []).toLocaleString('pt-BR', { minimumFractionDigits: 2 })}
Total Geral R$ {calculateTotal(currentProposal.items || []).toLocaleString('pt-BR', { minimumFractionDigits: 2 })}
{/* Footer Notes */}

Termos e Condições

{currentProposal.notes}

{/* Signature Area */}

{tenant.name}

Assinatura do Emissor

{client?.name || 'Cliente'}

De acordo

); } // LIST VIEW return (

Propostas Comerciais

Crie orçamentos e gerencie negociações.

{/* Toolbar */}
setSearchTerm(e.target.value)} className="w-full pl-10 pr-4 py-2.5 bg-slate-50 border-none rounded-xl focus:ring-2 focus:ring-primary-500 outline-none text-slate-600" />
{/* Table */}
{proposals.filter(p => p.clientName.toLowerCase().includes(searchTerm.toLowerCase()) || p.number.toLowerCase().includes(searchTerm.toLowerCase())).map(prop => ( ))}
Número Cliente Emissão Valor Status
{prop.number} {prop.clientName}
{new Date(prop.issueDate).toLocaleDateString('pt-BR')}
R$ {prop.totalValue.toLocaleString('pt-BR')} {prop.status === 'accepted' ? 'Aceito' : prop.status === 'sent' ? 'Enviado' : prop.status === 'rejected' ? 'Rejeitado' : 'Rascunho'}
{proposals.length === 0 && (

Nenhuma proposta registrada.

)}
); };