"use client"; import { useEffect, useMemo, useState, useRef } from "react"; import Dashboard from "../components/Dashboard"; import TenderSearch from "../components/TenderSearch"; import CompanyProfile from "../components/CompanyProfile"; import AgentAnalysis from "../components/AgentAnalysis"; import ProposalDraft from "../components/ProposalDraft"; import Reports from "../components/Reports"; import Sidebar from "../components/Sidebar"; import AnalysisHistory from "../components/AnalysisHistory"; import GlobalSync from "../components/GlobalSync"; import MarketMonitor from "../components/MarketMonitor"; import SystemInfo from "../components/SystemInfo"; import DBManager from "../components/DBManager"; import Documentation from "../components/Documentation"; import { analyzeTender, fetchAnalysisHistory, fetchCompanyProfile, healthCheck, saveCompanyProfile, searchTenders } from "../lib/api"; import type { AnalysisHistoryItem, AnalysisResult, CompanyProfile as CompanyProfileType, Tender } from "../lib/types"; import { translations, Language } from "../lib/translations"; const tabs = [ "Dashboard", "Tender Search", "My Portfolio", "Market Monitor", "Company Profile", "Agent Analysis", "Proposal Draft", "History", "Documentation", "Database", "About", ] as const; type Tab = (typeof tabs)[number]; export default function HomePage() { const [activeTab, setActiveTab] = useState("Dashboard"); const [showSync, setShowSync] = useState(true); const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); const [tenders, setTenders] = useState([]); const [selectedTender, setSelectedTender] = useState(null); const [companyProfile, setCompanyProfile] = useState({ name: "Andes Digital", industry: "Software development", services: ["AI automation", "web apps", "data dashboards"], experience: "5 years building enterprise software", certifications: [], regions: ["Metropolitana", "Valparaíso"], documents_available: ["RUT", "Portfolio", "Financial Statements"], keywords: ["software", "IA", "automatización"], }); const [analysisResult, setAnalysisResult] = useState(null); const [analysisHistory, setAnalysisHistory] = useState([]); const [searchHistory, setSearchHistory] = useState([]); const [status, setStatus] = useState("listening"); const [searchKeyword, setSearchKeyword] = useState(""); const [lang, setLang] = useState("en"); const [followedCount, setFollowedCount] = useState(0); const contentRef = useRef(null); // Sync followed count from localStorage useEffect(() => { const updateFollowed = () => { const saved = localStorage.getItem('andes_followed_tenders_full'); if (saved) { setFollowedCount(JSON.parse(saved).length); } }; updateFollowed(); window.addEventListener('storage', updateFollowed); // Also poll slightly for local changes if needed const interval = setInterval(updateFollowed, 2000); return () => { window.removeEventListener('storage', updateFollowed); clearInterval(interval); }; }, []); const t = translations[lang]; const handleGlobalSyncComplete = useMemo(() => () => setShowSync(false), []); // Scroll to top when tab changes useEffect(() => { // Force immediate scroll window.scrollTo({ top: 0, left: 0, behavior: 'instant' }); if (contentRef.current) { contentRef.current.scrollTo({ top: 0, left: 0, behavior: 'instant' }); } // Safety delay for async renders const timer = setTimeout(() => { window.scrollTo(0, 0); if (contentRef.current) contentRef.current.scrollTo(0, 0); }, 100); return () => clearTimeout(timer); }, [activeTab]); useEffect(() => { if (typeof window !== 'undefined') { const params = new URLSearchParams(window.location.search); const tabParam = params.get('tab'); if (tabParam) { const foundTab = tabs.find(t => t.toLowerCase().replace(/ /g, "_") === tabParam); if (foundTab) setActiveTab(foundTab); } } async function init(retries = 10) { try { const health = await healthCheck(); console.log("!!! HEALTH CHECK SUCCESS !!!", health); const mpStatus = health.dependencies?.mercado_publico; if (mpStatus === "connected") { setStatus("connected"); } else { setStatus("warning"); // Backend is up, but MP is not fully reachable } } catch (e) { console.error("Connection attempt failed", e); if (retries > 0) { setStatus("listening"); setTimeout(() => init(retries - 1), 5000); return; } setStatus("error"); } try { const profile = await fetchCompanyProfile(); if (profile) { // HYBRID PERSISTENCE CHECK: If backend is default but we have a local backup, restore it const localBackup = localStorage.getItem('andes_profile_backup'); if (profile.name === "Andes Digital" && localBackup) { console.log("!!! PERSISTENCE: Restoring profile from local backup !!!"); const backupData = JSON.parse(localBackup); await saveCompanyProfile(backupData); setCompanyProfile(backupData); } else { setCompanyProfile(profile); // Update backup if we got fresh real data if (profile.name !== "Andes Digital") { localStorage.setItem('andes_profile_backup', JSON.stringify(profile)); } } } } catch (e) { console.error("Profile load error", e); } try { let history = await fetchAnalysisHistory(); if (history.length === 0) { const localHistory = localStorage.getItem('andes_analysis_history_backup'); if (localHistory) history = JSON.parse(localHistory); } setAnalysisHistory(history); } catch (e) { console.error("History load error", e); } try { const { fetchSearchHistory } = await import("../lib/api"); let sHistory = await fetchSearchHistory(); if (sHistory.length === 0) { const localSearch = localStorage.getItem('andes_search_history_backup'); if (localSearch) sHistory = JSON.parse(localSearch); } setSearchHistory(sHistory); } catch (e) { console.error("Search history load error", e); } try { const initialTenders = await searchTenders({}); setTenders(initialTenders); } catch (e) { console.error("Tenders load error", e); } } init(); }, []); // Backup history to localStorage to survive HF Space restarts useEffect(() => { if (analysisHistory.length > 0) { localStorage.setItem('andes_analysis_history_backup', JSON.stringify(analysisHistory)); } }, [analysisHistory]); useEffect(() => { if (searchHistory.length > 0) { localStorage.setItem('andes_search_history_backup', JSON.stringify(searchHistory)); } }, [searchHistory]); const handleTenderSelect = (tender: Tender) => { setSelectedTender(tender); setActiveTab("Agent Analysis"); window.history.pushState({}, '', `?tab=agent_analysis`); }; const handleFilterClick = (type: "sector" | "region" | "buyer", value: string) => { setSearchKeyword(value); setActiveTab("Tender Search"); if (type === "buyer") { handleSearch({ buyer: value }); } else { handleSearch({ keyword: value }); } window.history.pushState({}, '', `?tab=tender_search&q=${encodeURIComponent(value)}`); }; const handleSearch = async (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 }) => { try { let results: Tender[]; if (params.isAgile && params.keyword) { const { scrapeTenders } = await import("../lib/api"); results = await scrapeTenders(params.keyword); } else { results = await searchTenders(params); } setTenders(results); // Log search to history if (params.keyword || params.code) { const { saveSearchHistory, fetchSearchHistory } = await import("../lib/api"); await saveSearchHistory(params.keyword || params.code || "Active Tenders", results.length, params.isAgile); const sHistory = await fetchSearchHistory(); setSearchHistory(sHistory); } } catch (error) { console.error("Search error:", error); } }; const handleProfileSave = async (profile: CompanyProfileType) => { try { const savedProfile = await saveCompanyProfile(profile); setCompanyProfile(savedProfile); // Sync with localStorage for hybrid persistence localStorage.setItem('andes_profile_backup', JSON.stringify(savedProfile)); console.log("!!! PERSISTENCE: Profile backed up to localStorage !!!"); } catch { setCompanyProfile(profile); } }; const handleRunAnalysis = async (documentText?: string, models?: Record, tenderDetails?: any, amdSettings?: { url: string, key: string }) => { if (!selectedTender) return; const result = await analyzeTender(selectedTender, companyProfile, documentText, models, tenderDetails, amdSettings); setAnalysisResult(result); try { const history = await fetchAnalysisHistory(); setAnalysisHistory(history); } catch (e) { console.error(e); } }; return (
{showSync && } {/* Mobile Header */}
A
AndesOps AI
{/* Sidebar Container */}
{isMobileMenuOpen && (
setIsMobileMenuOpen(false)} /> )}
{ setActiveTab(tab); setIsMobileMenuOpen(false); }} status={status} lang={lang} forceExpanded={isMobileMenuOpen} />
{/* Main Content */}
{/* Dashboard Header */}

{activeTab === "Dashboard" && t.dashboard} {activeTab === "Tender Search" && t.tenderSearch} {activeTab === "My Portfolio" && t.myPortfolio} {activeTab === "Market Monitor" && t.marketMonitor} {activeTab === "Company Profile" && t.companyProfile} {activeTab === "Agent Analysis" && t.agentAnalysis} {activeTab === "Proposal Draft" && t.proposalDraft} {activeTab === "History" && t.history} {activeTab === "Documentation" && t.documentation} {activeTab === "Database" && t.database} {activeTab === "About" && t.about}

{activeTab === "Dashboard" && (lang === 'es' ? 'Vista general de tu ecosistema de licitaciones.' : 'Overview of your tender ecosystem.')} {activeTab === "Tender Search" && (lang === 'es' ? 'Explora nuevas oportunidades del mercado.' : 'Explore new opportunities from the market.')} {activeTab === "Agent Analysis" && (lang === 'es' ? 'Análisis profundo de la documentación.' : 'Deep-dive into tender documentation.')} {activeTab === "My Portfolio" && (lang === 'es' ? 'Gestiona tus oportunidades seguidas.' : 'Manage your followed opportunities.')} {activeTab === "Market Monitor" && (lang === 'es' ? 'Seguimiento en vivo de órdenes de compra.' : 'Live tracking of purchase orders.')} {activeTab === "Company Profile" && (lang === 'es' ? 'Define tu estrategia comercial.' : 'Define your commercial strategy.')} {activeTab === "History" && (lang === 'es' ? 'Revisa tus análisis previos.' : 'Review your previous analyses.')} {activeTab === "Documentation" && (lang === 'es' ? 'Guía de uso y detalles técnicos.' : 'User guide and technical details.')} {activeTab === "Database" && (lang === 'es' ? 'Gestión de datos y sincronización.' : 'Data management and synchronization.')} {activeTab === "About" && (lang === 'es' ? 'Detalles del sistema y arquitectura.' : 'System details and architecture.')}

{/* ESG Monitor */}
{t.esgScore}
E 92
S 85
G 96
{/* Content Area */}
{activeTab === "Dashboard" && ( r.severity === "High").length ?? 0} reportsGenerated={analysisHistory.length} followedTendersCount={followedCount} tenders={tenders} onFilterClick={handleFilterClick} onTenderClick={handleTenderSelect} lang={lang} /> )} {(activeTab === "Tender Search" || activeTab === "My Portfolio") && ( )} {activeTab === "Market Monitor" && } {activeTab === "Company Profile" && ( )} {activeTab === "Agent Analysis" && ( setActiveTab("Tender Search")} lang={lang} /> )} {activeTab === "Proposal Draft" && } {activeTab === "History" && } {activeTab === "Documentation" && } {activeTab === "Database" && } {activeTab === "About" && }
); }