"use client"; import { useEffect, useState } from "react"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Skeleton } from "@/components/ui/skeleton"; import { CheckCircle2, AlertTriangle, HelpCircle, Users, Lightbulb, Wrench, AlertCircle, Sparkles, X, Plus, Save, Edit2 } from "lucide-react"; import { cn } from "@/lib/utils"; import { auth } from "@/lib/firebase/config"; import { toast } from "sonner"; interface ExtractionHandoff { phase: string; readyForNextPhase: boolean; confidence: number; confirmed: { problems?: string[]; targetUsers?: string[]; features?: string[]; constraints?: string[]; opportunities?: string[]; }; uncertain: Record; missing: string[]; questionsForUser: string[]; timestamp: string; } interface ExtractionResultsEditableProps { projectId: string; className?: string; } export function ExtractionResultsEditable({ projectId, className }: ExtractionResultsEditableProps) { const [extraction, setExtraction] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [isEditing, setIsEditing] = useState(false); const [isSaving, setIsSaving] = useState(false); // Local editable state const [editedProblems, setEditedProblems] = useState([]); const [editedUsers, setEditedUsers] = useState([]); const [editedFeatures, setEditedFeatures] = useState([]); const [editedConstraints, setEditedConstraints] = useState([]); const [editedOpportunities, setEditedOpportunities] = useState([]); useEffect(() => { const fetchExtraction = async () => { try { setLoading(true); const response = await fetch(`/api/projects/${projectId}/extraction-handoff`); if (!response.ok) { if (response.status === 404) { setExtraction(null); return; } throw new Error(`Failed to fetch extraction: ${response.statusText}`); } const data = await response.json(); const handoff = data.handoff; setExtraction(handoff); // Initialize editable state setEditedProblems(handoff.confirmed.problems || []); setEditedUsers(handoff.confirmed.targetUsers || []); setEditedFeatures(handoff.confirmed.features || []); setEditedConstraints(handoff.confirmed.constraints || []); setEditedOpportunities(handoff.confirmed.opportunities || []); } catch (err) { console.error("[ExtractionResults] Error:", err); setError(err instanceof Error ? err.message : "Failed to load extraction"); } finally { setLoading(false); } }; if (projectId) { fetchExtraction(); } }, [projectId]); const handleSave = async () => { setIsSaving(true); try { const user = auth.currentUser; if (!user) { toast.error("Please sign in to save changes"); return; } const token = await user.getIdToken(); const response = await fetch(`/api/projects/${projectId}/extraction-handoff`, { method: "PATCH", headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, body: JSON.stringify({ confirmed: { problems: editedProblems.filter(p => p.trim()), targetUsers: editedUsers.filter(u => u.trim()), features: editedFeatures.filter(f => f.trim()), constraints: editedConstraints.filter(c => c.trim()), opportunities: editedOpportunities.filter(o => o.trim()), }, }), }); if (!response.ok) { throw new Error("Failed to save changes"); } // Update local state if (extraction) { setExtraction({ ...extraction, confirmed: { problems: editedProblems.filter(p => p.trim()), targetUsers: editedUsers.filter(u => u.trim()), features: editedFeatures.filter(f => f.trim()), constraints: editedConstraints.filter(c => c.trim()), opportunities: editedOpportunities.filter(o => o.trim()), }, }); } setIsEditing(false); toast.success("Changes saved"); } catch (err) { console.error("[ExtractionResults] Save error:", err); toast.error("Failed to save changes"); } finally { setIsSaving(false); } }; const handleCancel = () => { // Reset to original values if (extraction) { setEditedProblems(extraction.confirmed.problems || []); setEditedUsers(extraction.confirmed.targetUsers || []); setEditedFeatures(extraction.confirmed.features || []); setEditedConstraints(extraction.confirmed.constraints || []); setEditedOpportunities(extraction.confirmed.opportunities || []); } setIsEditing(false); }; const renderEditableList = ( items: string[], setItems: (items: string[]) => void, Icon: any, iconColor: string, title: string ) => { const safeItems = items || []; return ( {title} {safeItems.map((item, index) => (
{isEditing ? ( <> { const newItems = [...items]; newItems[index] = e.target.value; setItems(newItems); }} className="flex-1 text-sm" /> ) : (

{item}

)}
))} {isEditing && ( )} {!isEditing && items.length === 0 && (

None

)}
); }; if (loading) { return (
); } if (error) { return (

{error}

); } if (!extraction) { return (

No extraction results yet

Upload documents and trigger extraction to see insights

); } return (
{/* Header */}
Extracted Insights

Review and edit the extracted information

{Math.round(extraction.confidence * 100)}% confidence {!isEditing ? ( ) : (
)}
{/* Editable Lists */} {renderEditableList(editedProblems, setEditedProblems, AlertTriangle, "text-orange-600", "Problems & Pain Points")} {renderEditableList(editedUsers, setEditedUsers, Users, "text-blue-600", "Target Users")} {renderEditableList(editedFeatures, setEditedFeatures, Lightbulb, "text-yellow-600", "Key Features")} {renderEditableList(editedConstraints, setEditedConstraints, Wrench, "text-purple-600", "Constraints & Requirements")} {renderEditableList(editedOpportunities, setEditedOpportunities, Sparkles, "text-green-600", "Opportunities")}
); }