"use client" import { useQuery } from "convex/react" import { useState } from "react" import { api } from "@/convex/_generated/api" import { useProject } from "@/components/project-context" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Badge } from "@/components/ui/badge" import { Alert, AlertDescription } from "@/components/ui/alert" import { Button } from "@/components/ui/button" import { useMutation } from "convex/react" import { Progress } from "@/components/ui/progress" export default function Page() { const { selectedProjectId } = useProject() const projects = useQuery(api.projects.getProjects) const dataSources = useQuery( api.dataSources.getProjectDataSources, selectedProjectId ? { projectId: selectedProjectId as any } : "skip" ) const searchContext = useQuery( api.projects.getSearchContext, selectedProjectId ? { projectId: selectedProjectId as any } : "skip" ) const analysisJobs = useQuery( api.analysisJobs.listByProject, selectedProjectId ? { projectId: selectedProjectId as any } : "skip" ) const updateDataSourceStatus = useMutation(api.dataSources.updateDataSourceStatus) const createAnalysis = useMutation(api.analyses.createAnalysis) const createAnalysisJob = useMutation(api.analysisJobs.create) const [reanalyzingId, setReanalyzingId] = useState(null) const analysis = useQuery( api.analyses.getLatestByProject, selectedProjectId ? { projectId: selectedProjectId as any } : "skip" ) const selectedProject = projects?.find((project) => project._id === selectedProjectId) const selectedSourceIds = selectedProject?.dorkingConfig?.selectedSourceIds || [] const isLoading = selectedProjectId && analysis === undefined if (!selectedProjectId && projects && projects.length === 0) { return (

No projects yet

Complete onboarding to create your first project.

) } if (isLoading) { return (
Loading analysis...
) } if (!analysis) { return (

No analysis yet

Run onboarding to analyze a product for this project.

) } const handleReanalyze = async (source: any) => { if (!selectedProjectId) return setReanalyzingId(source._id) await updateDataSourceStatus({ dataSourceId: source._id, analysisStatus: "pending", lastError: undefined, lastAnalyzedAt: undefined, }) try { const jobId = await createAnalysisJob({ projectId: selectedProjectId as any, dataSourceId: source._id, }) const response = await fetch("/api/analyze", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ url: source.url, jobId }), }) const data = await response.json() if (!response.ok) { await updateDataSourceStatus({ dataSourceId: source._id, analysisStatus: "failed", lastError: data.error || "Analysis failed", lastAnalyzedAt: Date.now(), }) return } await createAnalysis({ projectId: selectedProjectId as any, dataSourceId: source._id, analysis: data.data, }) await updateDataSourceStatus({ dataSourceId: source._id, analysisStatus: "completed", lastError: undefined, lastAnalyzedAt: Date.now(), }) } finally { setReanalyzingId(null) } } return (

{selectedProject?.name || analysis.productName}

{analysis.productName}

{analysis.tagline}

{analysis.description}

{searchContext?.missingSources?.length > 0 && ( Some selected sources don't have analysis yet:{" "} {searchContext.missingSources .map((missing: any) => dataSources?.find((source: any) => source._id === missing.sourceId)?.name || dataSources?.find((source: any) => source._id === missing.sourceId)?.url || missing.sourceId ) .join(", ")} . Run onboarding or re-analyze them for best results. )}
Features {analysis.features.length} Keywords {analysis.keywords.length} Personas {analysis.personas.length} Competitors {analysis.competitors.length} Use Cases {analysis.useCases.length}
Data Sources {dataSources && dataSources.length > 0 ? ( dataSources.map((source: any) => (
{source.name || source.url}
{selectedSourceIds.includes(source._id) ? "active" : "inactive"} {source.analysisStatus}
)) ) : (

No data sources yet. Add a source during onboarding.

)}
{analysisJobs && analysisJobs.length > 0 && ( Analysis Jobs {analysisJobs.slice(0, 5).map((job: any) => { const sourceName = dataSources?.find((source: any) => source._id === job.dataSourceId)?.name || dataSources?.find((source: any) => source._id === job.dataSourceId)?.url || "Unknown source" return (
{sourceName}{" "} ({job.status})
{job.status === "failed" && ( )}
{(job.status === "running" || job.status === "pending") && (
{typeof job.progress === "number" ? `${job.progress}% complete` : "Starting..."}
)} {job.status === "failed" && job.error && (
{job.error}
)}
) })}
)} {searchContext?.context && ( Aggregated Context
Keywords: {searchContext.context.keywords.length}
Problems: {searchContext.context.problemsSolved.length}
Competitors: {searchContext.context.competitors.length}
Use Cases: {searchContext.context.useCases.length}
)}
Top Features {analysis.features.slice(0, 6).map((feature, index) => (

{feature.name}

{feature.description}

))}
Top Problems Solved {analysis.problemsSolved.slice(0, 6).map((problem, index) => (

{problem.problem}

{problem.emotionalImpact}

))}
) }