import { useState } from 'react'; import { Plus, Pencil, Trash2, Search, Send } from 'lucide-react'; import { useProposals, useDeleteProposal, useCreateProposal, useUpdateProposal, useSubmitProposal, useTenders, } from '../../../hooks/useBidding'; import { Proposal, ProposalStatus, CreateProposalDto, } from '../../../services/bidding'; import clsx from 'clsx'; const statusColors: Record = { draft: 'bg-gray-100 text-gray-800', submitted: 'bg-blue-100 text-blue-800', under_review: 'bg-yellow-100 text-yellow-800', accepted: 'bg-green-100 text-green-800', rejected: 'bg-red-100 text-red-800', }; const statusLabels: Record = { draft: 'Borrador', submitted: 'Enviada', under_review: 'En Revision', accepted: 'Aceptada', rejected: 'Rechazada', }; const allStatuses: ProposalStatus[] = ['draft', 'submitted', 'under_review', 'accepted', 'rejected']; export function ProposalsPage() { const [search, setSearch] = useState(''); const [statusFilter, setStatusFilter] = useState(''); const [showModal, setShowModal] = useState(false); const [editingItem, setEditingItem] = useState(null); const [deleteConfirm, setDeleteConfirm] = useState(null); const [submitConfirm, setSubmitConfirm] = useState(null); const { data, isLoading, error } = useProposals({ status: statusFilter || undefined, }); const deleteMutation = useDeleteProposal(); const createMutation = useCreateProposal(); const updateMutation = useUpdateProposal(); const submitMutation = useSubmitProposal(); const handleDelete = async (id: string) => { await deleteMutation.mutateAsync(id); setDeleteConfirm(null); }; const handleSubmit = async (formData: CreateProposalDto) => { if (editingItem) { await updateMutation.mutateAsync({ id: editingItem.id, data: formData }); } else { await createMutation.mutateAsync(formData); } setShowModal(false); setEditingItem(null); }; const handleSubmitProposal = async (id: string) => { await submitMutation.mutateAsync(id); setSubmitConfirm(null); }; const proposals = data?.items || []; const filteredProposals = search ? proposals.filter((p) => p.proposalNumber.toLowerCase().includes(search.toLowerCase()) || p.tender?.title.toLowerCase().includes(search.toLowerCase()) ) : proposals; const formatCurrency = (value: number) => { return new Intl.NumberFormat('es-MX', { style: 'currency', currency: 'MXN', }).format(value); }; return (

Propuestas

Gestion de propuestas tecnicas y economicas

{/* Filters */}
setSearch(e.target.value)} />
{/* Table */}
{isLoading ? (
Cargando...
) : error ? (
Error al cargar los datos
) : filteredProposals.length === 0 ? (
No hay propuestas
) : ( {filteredProposals.map((item) => ( ))}
No. Propuesta Licitacion Monto Total Punt. Tecnico Punt. Economico Estado Acciones
{item.proposalNumber} {item.tender?.title || '-'} {formatCurrency(item.totalAmount)} {item.technicalScore !== undefined ? `${item.technicalScore} pts` : '-'} {item.economicScore !== undefined ? `${item.economicScore} pts` : '-'} {statusLabels[item.status]}
{item.status === 'draft' && ( )}
)}
{/* Modal */} {showModal && ( { setShowModal(false); setEditingItem(null); }} onSubmit={handleSubmit} isLoading={createMutation.isPending || updateMutation.isPending} /> )} {/* Submit Confirmation */} {submitConfirm && (

Confirmar envio

¿Esta seguro de enviar esta propuesta? Una vez enviada no podra modificarse.

)} {/* Delete Confirmation */} {deleteConfirm && (

Confirmar eliminacion

¿Esta seguro de eliminar esta propuesta? Esta accion no se puede deshacer.

)}
); } // Modal Component interface ProposalModalProps { item: Proposal | null; onClose: () => void; onSubmit: (data: CreateProposalDto) => Promise; isLoading: boolean; } function ProposalModal({ item, onClose, onSubmit, isLoading }: ProposalModalProps) { const { data: tendersData } = useTenders({ status: 'published' }); const tenders = tendersData?.items || []; const [formData, setFormData] = useState({ tenderId: item?.tenderId || '', proposalNumber: item?.proposalNumber || '', totalAmount: item?.totalAmount || 0, technicalScore: item?.technicalScore, economicScore: item?.economicScore, status: item?.status || 'draft', }); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); await onSubmit(formData); }; return (

{item ? 'Editar Propuesta' : 'Nueva Propuesta'}

setFormData({ ...formData, proposalNumber: e.target.value })} />
setFormData({ ...formData, totalAmount: parseFloat(e.target.value) || 0 })} />
setFormData({ ...formData, technicalScore: e.target.value ? parseFloat(e.target.value) : undefined })} />
setFormData({ ...formData, economicScore: e.target.value ? parseFloat(e.target.value) : undefined })} />
); }