"use client"; import { useMemo, useState, useRef, useEffect } from "react"; import BrandLoader from "./BrandLoader"; import type { Tender } from "../lib/types"; import { Language, translations } from "../lib/translations"; import AgentChat from "./AgentChat"; import type { CompanyProfile } from "../lib/types"; type Props = { tenders: Tender[]; onSearch: (params: { keyword?: string; buyer?: string; provider_code?: string; org_code?: string; status?: string; code?: string; date?: string; type_code?: string; skip?: number; limit?: number; isAgile?: boolean }) => void; onAnalyze: (tender: Tender) => void; forceShowFollowed?: boolean; initialKeyword?: string; lang: Language; companyProfile: CompanyProfile; }; export default function TenderSearch({ tenders, onSearch, onAnalyze, forceShowFollowed = false, initialKeyword = "", lang, companyProfile }: Props) { const t = translations[lang]; const [keyword, setKeyword] = useState(initialKeyword); const [buyerCode, setBuyerCode] = useState(""); const [providerCode, setProviderCode] = useState(""); const [orgCode, setOrgCode] = useState(""); const [status, setStatus] = useState(""); const [date, setDate] = useState(""); const [typeCode, setTypeCode] = useState(""); const [showAdvanced, setShowAdvanced] = useState(false); const [selectedTenderForModal, setSelectedTenderForModal] = useState(null); const [selectedCodes, setSelectedCodes] = useState([]); const [isSyncingToAgents, setIsSyncingToAgents] = useState(false); const [activeDetailTab, setActiveDetailTab] = useState<"Overview" | "Agent Chat">("Overview"); const [followedTenders, setFollowedTenders] = useState(() => { if (typeof window !== 'undefined') { const saved = localStorage.getItem('andes_followed_tenders_full'); return saved ? JSON.parse(saved) : []; } return []; }); const followedCodes = useMemo(() => followedTenders.map(item => item.code), [followedTenders]); const [showOnlyFollowed, setShowOnlyFollowed] = useState(forceShowFollowed); const [isLoading, setIsLoading] = useState(false); const [isAgileMode, setIsAgileMode] = useState(false); const isSearchPending = useRef(false); const filteredTenders = useMemo(() => { if (showOnlyFollowed) return followedTenders; let list = tenders; if (isAgileMode) { list = list.filter(item => item.code.includes('COT26') || item.name.toLowerCase().includes('compra Γ‘gil') || item.sector?.toLowerCase().includes('agil') ); } return list; }, [tenders, showOnlyFollowed, followedTenders, isAgileMode]); useEffect(() => { if (forceShowFollowed) setShowOnlyFollowed(true); }, [forceShowFollowed]); useEffect(() => { localStorage.setItem('andes_followed_tenders_full', JSON.stringify(followedTenders)); }, [followedTenders]); const toggleFollow = (tender: Tender) => { setFollowedTenders(prev => { const isFollowing = prev.some(item => item.code === tender.code); return isFollowing ? prev.filter(item => item.code !== tender.code) : [...prev, tender]; }); }; const handleSearch = async (e?: React.FormEvent) => { if (e) e.preventDefault(); if (isSearchPending.current) return; isSearchPending.current = true; setIsLoading(true); try { const isCode = /^[0-9]+-[0-9]+-[A-Z0-9]+$/i.test(keyword); const searchParams = { keyword: isCode ? undefined : keyword, code: isCode ? keyword : undefined, org_code: orgCode || undefined, status: status || undefined, type_code: typeCode || undefined, date, skip: 0, limit: 50, isAgile: isAgileMode }; console.log("[TenderSearch] Searching with params:", searchParams); await onSearch(searchParams); } catch (error) { console.error("[TenderSearch] Search failed:", error); const errorMsg = error instanceof Error ? error.message : "Search failed. Check your backend connection."; alert(`Search Error: ${errorMsg}`); } finally { setIsLoading(false); isSearchPending.current = false; } }; const isTenderCode = /^[0-9]+-[0-9]+-[A-Z0-9]+$/i.test(keyword); const isLiveSearch = Boolean(isTenderCode || orgCode || status || date || typeCode); const searchButtonLabel = isLoading ? "Searching..." : isLiveSearch ? "Live MP Search" : "Fetch Active Tenders"; // VIEW: Search & List const renderListView = () => (
{forceShowFollowed ? "β˜…" : "πŸ“‘"}

{forceShowFollowed ? "My Portfolio" : "Tender Discovery"}

Real-time access to the Chilean public procurement market.

{!forceShowFollowed && (
setKeyword(e.target.value)} />
{showAdvanced && (
setDate(e.target.value)} />
setOrgCode(e.target.value)} />
)}
)}
{filteredTenders.map((item) => ( ))}
ID Opportunity Buyer Status Action
{item.code}
{item.name}
{item.buyer}
{item.buyer} {item.status}
); // VIEW: Detail Modal const renderDetailView = (tender: Tender) => (
{activeDetailTab === "Overview" ? (
{tender.code} {tender.status} {tender.type || "N/A"}

{tender.name}

{tender.buyer}

Estimated Investment

{tender.estimated_amount ? new Intl.NumberFormat("es-CL", { style: "currency", currency: tender.currency || "CLP", maximumFractionDigits: 0 }).format(tender.estimated_amount) : "N/A"}

Closing Deadline

{tender.closing_date ? new Date(tender.closing_date).toLocaleDateString() : "---"}

Region

{tender.region || "Nacional"}

Sector

{tender.sector || "General"}

Detailed Description

{tender.description || "No description provided."}
{tender.evaluation_criteria && tender.evaluation_criteria.length > 0 && (

βš–οΈ Evaluation Criteria

{tender.evaluation_criteria.map((crit, idx) => (
{crit.weight}%
{crit.name} {crit.weight}%
{crit.description &&

{crit.description}

}
))}
)} {/* Lifecycle Section */}

πŸ”„ Procurement Lifecycle

{[ { label: "Preguntas", icon: "❓", status: "Active" }, { label: "Historial", icon: "πŸ“œ", status: "Available" }, { label: "Apertura", icon: "πŸ”“", status: "Pending" }, { label: "AdjudicaciΓ³n", icon: "πŸ†", status: "Future" } ].map((step, i) => (
{step.icon}
{step.label}
{step.status}
))}
{tender.items && tender.items.length > 0 && (

Products / Services Required

{tender.items.map((item, idx) => ( ))}
Item Name Quantity
{item.name} {item.quantity} {item.unit}
)}

Decision Intelligence

Launch our multi-agent AI pipeline to analyze compliance, risks, and win-probability for this opportunity.

Documents & Attachments

{tender.attachments && tender.attachments.length > 0 ? (
{tender.attachments.map((att, idx) => (
πŸ“„ {att.name}
πŸ“₯
))}
) : (
πŸ“„

No direct attachments found. Check the official site for the full bidding package.

)}
) : ( )}
); return (
{selectedTenderForModal ? renderDetailView(selectedTenderForModal) : renderListView()} {isLoading && }
); }