VIBN Frontend for Coolify deployment
This commit is contained in:
129
components/ai/extraction-review-checklist.tsx
Normal file
129
components/ai/extraction-review-checklist.tsx
Normal file
@@ -0,0 +1,129 @@
|
||||
"use client";
|
||||
|
||||
import { CheckCircle2, Circle } from "lucide-react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { db } from "@/lib/firebase/config";
|
||||
import { doc, onSnapshot } from "firebase/firestore";
|
||||
|
||||
interface ExtractionReviewChecklistProps {
|
||||
projectId: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function ExtractionReviewChecklist({ projectId, className }: ExtractionReviewChecklistProps) {
|
||||
const [hasProblems, setHasProblems] = useState(false);
|
||||
const [hasUsers, setHasUsers] = useState(false);
|
||||
const [hasFeatures, setHasFeatures] = useState(false);
|
||||
const [reviewedWithAI, setReviewedWithAI] = useState(false);
|
||||
const [readyForVision, setReadyForVision] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!projectId) return;
|
||||
|
||||
const unsubscribe = onSnapshot(
|
||||
doc(db, "projects", projectId),
|
||||
(snapshot) => {
|
||||
if (snapshot.exists()) {
|
||||
const data = snapshot.data();
|
||||
const extraction = data?.phaseData?.phaseHandoffs?.extraction;
|
||||
|
||||
if (extraction) {
|
||||
// Check if we have key data
|
||||
setHasProblems((extraction.confirmed?.problems?.length || 0) > 0);
|
||||
setHasUsers((extraction.confirmed?.targetUsers?.length || 0) > 0);
|
||||
setHasFeatures((extraction.confirmed?.features?.length || 0) > 0);
|
||||
setReadyForVision(extraction.readyForNextPhase || false);
|
||||
}
|
||||
|
||||
// Check if user has reviewed with AI (simplified: check if there are any messages in chat)
|
||||
// This is a placeholder - you might track this differently
|
||||
setReviewedWithAI(data?.lastChatAt ? true : false);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return () => unsubscribe();
|
||||
}, [projectId]);
|
||||
|
||||
const checklist = [
|
||||
{
|
||||
id: "problems",
|
||||
label: "Problems identified",
|
||||
checked: hasProblems,
|
||||
},
|
||||
{
|
||||
id: "users",
|
||||
label: "Target users defined",
|
||||
checked: hasUsers,
|
||||
},
|
||||
{
|
||||
id: "features",
|
||||
label: "Key features extracted",
|
||||
checked: hasFeatures,
|
||||
},
|
||||
{
|
||||
id: "reviewed",
|
||||
label: "Reviewed with AI",
|
||||
checked: reviewedWithAI,
|
||||
},
|
||||
];
|
||||
|
||||
const completedCount = checklist.filter((item) => item.checked).length;
|
||||
const progress = (completedCount / checklist.length) * 100;
|
||||
const isCompleted = completedCount === checklist.length || readyForVision;
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
{/* Header */}
|
||||
<div className="mb-3">
|
||||
<h3 className="text-sm font-semibold">
|
||||
{isCompleted ? '✓ Review Complete' : 'Extraction Review'}
|
||||
</h3>
|
||||
<div className="mt-2">
|
||||
<div className="w-full bg-secondary h-2 rounded-full overflow-hidden">
|
||||
<div
|
||||
className="h-full bg-primary transition-all duration-300"
|
||||
style={{ width: `${isCompleted ? 100 : progress}%` }}
|
||||
/>
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground mt-1">
|
||||
{isCompleted ? `${checklist.length} of ${checklist.length} complete` : `${completedCount} of ${checklist.length} complete`}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Checklist Items */}
|
||||
<div className="space-y-2">
|
||||
{checklist.map((item) => (
|
||||
<div
|
||||
key={item.id}
|
||||
className={`flex items-center gap-2 py-2 px-3 rounded-md border ${
|
||||
(item.checked || isCompleted)
|
||||
? "bg-green-50 border-green-200"
|
||||
: "bg-muted/50 border-muted text-muted-foreground opacity-60"
|
||||
}`}
|
||||
>
|
||||
{(item.checked || isCompleted) ? (
|
||||
<CheckCircle2 className="h-4 w-4 text-green-600 flex-shrink-0" />
|
||||
) : (
|
||||
<Circle className="h-4 w-4 text-muted-foreground flex-shrink-0" />
|
||||
)}
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-xs font-medium">{item.label}</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Ready indicator */}
|
||||
{readyForVision && (
|
||||
<div className="mt-4 pt-4 border-t">
|
||||
<p className="text-xs text-green-600 font-medium">
|
||||
✓ Ready for Vision phase
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user