/** * Analysis page */ "use client"; import { useEffect, useCallback, useRef } from "react"; import { useRouter } from "next/navigation"; import { AnalysisForm } from "@/components/analysis/AnalysisForm"; import { LoadingSpinner } from "@/components/shared/LoadingSpinner"; import { ErrorAlert } from "@/components/shared/ErrorAlert"; import { useAnalysis } from "@/hooks/useAnalysis"; import { useAnalysisContext } from "@/context/AnalysisContext"; import { useAuth } from "@/contexts/auth-context"; import { useLanguage } from "@/contexts/LanguageContext"; import { saveReport, checkDuplicateReport } from "@/lib/reports-db"; import { saveCloudReport, isCloudSyncEnabled } from "@/lib/user-api"; import type { AnalysisRequest } from "@/lib/types"; export default function AnalysisPage() { const router = useRouter(); const { setAnalysisResult, setTaskId, setMarketType, marketType } = useAnalysisContext(); const { runAnalysis, loading, error, result, taskId } = useAnalysis(); const { isAuthenticated } = useAuth(); const { t, locale } = useLanguage(); // Ref to track if we've already saved (to prevent duplicate saves) const hasSavedRef = useRef(false); // Auto-save function const autoSaveReport = useCallback(async () => { if (!result || hasSavedRef.current) return; try { // Check for duplicate const duplicate = await checkDuplicateReport(result.ticker, result.analysis_date); if (duplicate) { console.log("Report already saved, skipping auto-save"); return; } // Mark as saved to prevent duplicate saves hasSavedRef.current = true; // Save to local IndexedDB await saveReport( result.ticker, marketType, result.analysis_date, result, taskId || undefined, locale as "en" | "zh-TW" // Pass current language for filtering ); console.log("📁 Auto-saved report to local storage"); // If authenticated, also save to cloud if (isAuthenticated && isCloudSyncEnabled()) { const cloudId = await saveCloudReport({ ticker: result.ticker, market_type: marketType, analysis_date: result.analysis_date, result: result, language: locale as "en" | "zh-TW", }); if (cloudId) { console.log("☁️ Auto-saved report to cloud"); } } // Note: Redis cleanup is handled immediately when analysis completes // in useAnalysis hook, so no need to cleanup here } catch (error) { console.error("Auto-save failed:", error); } }, [result, marketType, taskId, isAuthenticated, locale]); // Auto-save when page unloads (closing tab, navigating away, etc.) useEffect(() => { const handleBeforeUnload = (e: BeforeUnloadEvent) => { if (result && !hasSavedRef.current) { // Trigger auto-save synchronously (best effort) autoSaveReport(); // Show browser's default "Leave site?" dialog only if there's unsaved analysis e.preventDefault(); e.returnValue = ''; } }; // Add listener when we have a result if (result) { window.addEventListener('beforeunload', handleBeforeUnload); } return () => { window.removeEventListener('beforeunload', handleBeforeUnload); }; }, [result, autoSaveReport]); // 當分析完成時自動跳轉到結果頁面 useEffect(() => { if (result && !loading && !error) { // Auto-save before navigating to results autoSaveReport(); setAnalysisResult(result); if (taskId) { setTaskId(taskId); } router.push("/analysis/results"); } }, [result, loading, error, router, setAnalysisResult, taskId, setTaskId, autoSaveReport]); const handleSubmit = async (data: AnalysisRequest) => { try { // Store the market type for later use when saving the report if (data.market_type) { setMarketType(data.market_type); } await runAnalysis(data); } catch (err) { // Error is handled by the hook console.error("Analysis failed:", err); } }; const handleViewResults = () => { if (result) { setAnalysisResult(result); router.push("/analysis/results"); } }; return (
{t.form.analysisSubtitle}