Files
vibn-frontend/components/mission/mission-idea-section.tsx

202 lines
6.5 KiB
TypeScript

"use client";
import { useState, useEffect } from "react";
import { Clock, History, Loader2 } from "lucide-react";
import { Button } from "@/components/ui/button";
import {
Sheet,
SheetContent,
SheetDescription,
SheetHeader,
SheetTitle,
SheetTrigger,
} from "@/components/ui/sheet";
import { ScrollArea } from "@/components/ui/scroll-area";
import { auth, db } from "@/lib/firebase/config";
import { doc, getDoc, collection, query, where, orderBy, getDocs } from "firebase/firestore";
import { formatDistanceToNow } from "date-fns";
interface MissionRevision {
id: string;
content: string;
updatedAt: Date;
updatedBy: string;
source: 'ai' | 'user';
}
interface MissionIdeaSectionProps {
projectId: string;
}
export function MissionIdeaSection({ projectId }: MissionIdeaSectionProps) {
const [loading, setLoading] = useState(true);
const [content, setContent] = useState("");
const [lastUpdated, setLastUpdated] = useState<Date | null>(null);
const [revisions, setRevisions] = useState<MissionRevision[]>([]);
const [loadingRevisions, setLoadingRevisions] = useState(false);
useEffect(() => {
if (projectId) {
fetchMissionIdea();
}
}, [projectId]);
const fetchMissionIdea = async () => {
setLoading(true);
try {
const user = auth.currentUser;
if (!user) return;
// Fetch current mission idea from project document
const projectRef = doc(db, 'projects', projectId);
const projectSnap = await getDoc(projectRef);
if (projectSnap.exists()) {
const data = projectSnap.data();
setContent(
data.missionIdea ||
"Help solo founders build and launch their products 10x faster by turning conversations into production-ready code, designs, and marketing."
);
setLastUpdated(data.missionIdeaUpdatedAt?.toDate() || null);
}
} catch (error) {
console.error('Error fetching mission idea:', error);
} finally {
setLoading(false);
}
};
const fetchRevisions = async () => {
setLoadingRevisions(true);
try {
const user = auth.currentUser;
if (!user) return;
// Fetch revision history
const revisionsRef = collection(db, 'missionRevisions');
const revisionsQuery = query(
revisionsRef,
where('projectId', '==', projectId),
orderBy('updatedAt', 'desc')
);
const revisionsSnap = await getDocs(revisionsQuery);
const revisionsList: MissionRevision[] = [];
revisionsSnap.forEach((doc) => {
const data = doc.data();
revisionsList.push({
id: doc.id,
content: data.content,
updatedAt: data.updatedAt?.toDate(),
updatedBy: data.updatedBy || 'AI',
source: data.source || 'ai',
});
});
setRevisions(revisionsList);
} catch (error) {
console.error('Error fetching revisions:', error);
} finally {
setLoadingRevisions(false);
}
};
if (loading) {
return (
<div className="flex items-center justify-center py-12">
<Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
</div>
);
}
return (
<div className="space-y-4">
{/* Content Card */}
<div className="rounded-lg border bg-card p-6">
<p className="text-xl font-medium leading-relaxed">
{content}
</p>
</div>
{/* Meta Information */}
<div className="flex items-center justify-between text-sm text-muted-foreground">
<div className="flex items-center gap-2">
<Clock className="h-4 w-4" />
<span>
{lastUpdated
? `Last updated ${formatDistanceToNow(lastUpdated, { addSuffix: true })} by AI`
: 'Not yet updated'}
</span>
</div>
{/* Revision History */}
<Sheet>
<SheetTrigger asChild>
<Button
variant="ghost"
size="sm"
onClick={fetchRevisions}
>
<History className="h-4 w-4 mr-2" />
View History
</Button>
</SheetTrigger>
<SheetContent className="w-[500px] sm:w-[600px]">
<SheetHeader>
<SheetTitle>Revision History</SheetTitle>
<SheetDescription>
See how your mission idea has evolved over time
</SheetDescription>
</SheetHeader>
<ScrollArea className="h-[calc(100vh-120px)] mt-6">
{loadingRevisions ? (
<div className="flex items-center justify-center py-12">
<Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
</div>
) : revisions.length === 0 ? (
<div className="text-center py-12 text-muted-foreground">
<History className="h-12 w-12 mx-auto mb-3 opacity-50" />
<p className="text-sm">No revision history yet</p>
</div>
) : (
<div className="space-y-4">
{revisions.map((revision, index) => (
<div
key={revision.id}
className="rounded-lg border bg-card p-4 space-y-2"
>
<div className="flex items-center justify-between text-xs text-muted-foreground">
<div className="flex items-center gap-2">
<span className="font-medium">
{revision.source === 'ai' ? 'AI Update' : 'Manual Edit'}
</span>
{index === 0 && (
<span className="px-2 py-0.5 rounded-full bg-primary/10 text-primary text-[10px] font-medium">
Current
</span>
)}
</div>
<span>
{formatDistanceToNow(revision.updatedAt, { addSuffix: true })}
</span>
</div>
<p className="text-sm leading-relaxed">
{revision.content}
</p>
<div className="text-xs text-muted-foreground">
{revision.updatedAt.toLocaleString()}
</div>
</div>
))}
</div>
)}
</ScrollArea>
</SheetContent>
</Sheet>
</div>
</div>
);
}