'use client'; import { use, useState, useEffect, useCallback } from 'react'; import { Card } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Loader2, CheckCircle2, Circle, Clock, RefreshCw, Eye, Cog, GitBranch, ChevronDown, ChevronRight } from 'lucide-react'; import { CollapsibleSidebar } from '@/components/ui/collapsible-sidebar'; interface WorkItem { id: string; title: string; category: string; path: string; status: 'built' | 'missing' | 'in_progress'; priority: string; assigned?: string; startDate: string | null; endDate: string | null; duration: number; sessionsCount: number; commitsCount: number; totalActivity: number; estimatedCost?: number; requirements: Array<{ id: number; text: string; status: 'built' | 'missing' | 'in_progress'; }>; evidence: string[]; note?: string; } interface TimelineData { workItems: WorkItem[]; timeline: { start: string; end: string; totalDays: number; }; summary: { totalWorkItems: number; withActivity: number; noActivity: number; built: number; missing: number; }; projectCreator?: string; } export default function TimelinePlanPage({ params, }: { params: Promise<{ workspace: string; projectId: string }>; }) { const { projectId } = use(params); const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [regenerating, setRegenerating] = useState(false); const [expandedItems, setExpandedItems] = useState>(new Set()); const [viewMode, setViewMode] = useState<'touchpoints' | 'technical' | 'journey'>('touchpoints'); const [collapsedJourneySections, setCollapsedJourneySections] = useState>(new Set()); // Map work items to types based on path and category const getWorkItemType = (item: WorkItem): string => { // API endpoints are System if (item.path.startsWith('/api/')) return 'System'; // Flows are Flow if (item.path.startsWith('flow/')) return 'Flow'; // Auth/OAuth is System if (item.path.includes('auth') || item.path.includes('oauth')) return 'System'; // Settings is System if (item.path.includes('settings')) return 'System'; // Marketing/Content pages if (item.category === 'Marketing' || item.category === 'Content') return 'Screen'; // Social if (item.category === 'Social') return 'Screen'; // Everything else is a Screen return 'Screen'; }; // Determine if item is a user-facing touchpoint const isTouchpoint = (item: WorkItem): boolean => { const path = item.path.toLowerCase(); const title = item.title.toLowerCase(); // Exclude APIs and backend systems if (path.startsWith('/api/')) return false; if (title.includes(' api') || title.includes('api ')) return false; // Exclude pure auth infrastructure (OAuth endpoints) if (path.includes('oauth') && !path.includes('button') && !path.includes('signin')) return false; // Include everything else - screens, pages, social posts, blogs, invites, etc. return true; }; // Determine if item is technical infrastructure const isTechnical = (item: WorkItem): boolean => { const path = item.path.toLowerCase(); const title = item.title.toLowerCase(); // APIs and backend if (path.startsWith('/api/')) return true; if (title.includes(' api') || title.includes('api ')) return true; // Auth infrastructure if (path.includes('oauth') && !path.includes('button') && !path.includes('signin')) return true; // System settings if (item.category === 'Settings' && title.includes('api')) return true; return false; }; // Map work items to customer lifecycle journey sections const getJourneySection = (item: WorkItem): string => { const title = item.title.toLowerCase(); const path = item.path.toLowerCase(); // Discovery - "I just found you online via social post, blog article, advertisement" if (path === '/' || title.includes('landing') || title.includes('marketing page')) return 'Discovery'; if (item.category === 'Social' && !path.includes('settings')) return 'Discovery'; if (item.category === 'Content' && (title.includes('blog') || title.includes('article'))) return 'Discovery'; // Research - "Checking out your marketing website - features, price, home page" if (title.includes('marketing dashboard')) return 'Research'; if (item.category === 'Marketing' && path !== '/') return 'Research'; if (path.includes('/features') || path.includes('/pricing') || path.includes('/about')) return 'Research'; if (item.category === 'Content' && path.includes('/docs') && !title.includes('getting started')) return 'Research'; // Onboarding - "Creating an account to try the product for the first time" if (path.includes('auth') || path.includes('oauth')) return 'Onboarding'; if (path.includes('signup') || path.includes('signin') || path.includes('login')) return 'Onboarding'; if (title.includes('authentication') && !title.includes('api')) return 'Onboarding'; // First Use - "Zero state to experiencing the magic solution" if (title.includes('onboarding')) return 'First Use'; if (title.includes('getting started')) return 'First Use'; if (path.includes('workspace') && !path.includes('settings')) return 'First Use'; if (title.includes('creation flow') || title.includes('project creation')) return 'First Use'; if (path.includes('/projects') && path.match(/\/projects\/?$/)) return 'First Use'; // Projects list page // Active - "I've seen the magic and come back to use it again and again" if (path.includes('overview') || path.includes('/dashboard')) return 'Active'; if (path.includes('timeline-plan') || path.includes('audit') || path.includes('mission')) return 'Active'; if (path.includes('/api/projects') || path.includes('mvp-checklist')) return 'Active'; if (title.includes('plan generation') || title.includes('marketing plan')) return 'Active'; if (path.includes('projects/') && path.length > '/projects/'.length) return 'Active'; // Specific project pages // Support - "I've got questions, need quick answers to get back to the magic" if (path.includes('settings')) return 'Support'; if (path.includes('/help') || path.includes('/faq') || path.includes('/support')) return 'Support'; if (item.category === 'Content' && path.includes('/docs') && title.includes('help')) return 'Support'; // Purchase - "Time to pay so I can keep using the magic" if (path.includes('billing') || path.includes('payment') || path.includes('subscription')) return 'Purchase'; if (path.includes('upgrade') || path.includes('checkout') || path.includes('pricing/buy')) return 'Purchase'; // Default to Active for core product features return 'Active'; }; const toggleJourneySection = (sectionId: string) => { setCollapsedJourneySections(prev => { const newSet = new Set(prev); if (newSet.has(sectionId)) { newSet.delete(sectionId); } else { newSet.add(sectionId); } return newSet; }); }; // Get emoji icon for journey section const getJourneySectionIcon = (section: string): string => { const icons: Record = { 'Discovery': '🔍', 'Research': '📚', 'Onboarding': '🎯', 'First Use': '🚀', 'Active': '⚡', 'Support': '💡', 'Purchase': '💳' }; return icons[section] || '📋'; }; // Get phase status based on overall item status const getPhaseStatus = (itemStatus: string, phase: 'scope' | 'design' | 'code'): 'built' | 'in_progress' | 'missing' => { if (itemStatus === 'built') return 'built'; if (itemStatus === 'missing') return 'missing'; // If in_progress, show progression through phases if (phase === 'scope') return 'built'; if (phase === 'design') return 'in_progress'; return 'missing'; }; // Render status badge const renderStatusBadge = (status: 'built' | 'in_progress' | 'missing') => { if (status === 'built') { return ( Done ); } if (status === 'in_progress') { return ( Started ); } return ( To-do ); }; const loadTimelineData = useCallback(async () => { try { setLoading(true); const response = await fetch(`/api/projects/${projectId}/timeline-view`); const result = await response.json(); // Check if the response is an error if (result.error) { console.error('API Error:', result.error, result.details); alert(`Failed to load timeline: ${result.details || result.error}`); return; } setData(result); } catch (error) { console.error('Error loading timeline:', error); alert('Failed to load timeline data. Check console for details.'); } finally { setLoading(false); } }, [projectId]); useEffect(() => { loadTimelineData(); }, [loadTimelineData]); const regeneratePlan = async () => { if (!confirm('Regenerate the plan? This will analyze your project and create a fresh MVP checklist.')) { return; } try { setRegenerating(true); const response = await fetch(`/api/projects/${projectId}/mvp-checklist`, { method: 'POST', }); if (!response.ok) { throw new Error('Failed to regenerate plan'); } // Reload the timeline data await loadTimelineData(); } catch (error) { console.error('Error regenerating plan:', error); alert('Failed to regenerate plan. Check console for details.'); } finally { setRegenerating(false); } }; if (loading) { return (
); } if (!data) { return
No timeline data available
; } return (
{/* Left Sidebar */}

Quick Stats

Total Items {data.summary.totalWorkItems}
Built {data.summary.built}
In Progress {data.summary.withActivity - data.summary.built}
To Build {data.summary.missing}
{/* Main Content */}
{/* Header */}

MVP Checklist

{data.summary.built} of {data.summary.totalWorkItems} pages built • {data.summary.withActivity} with development activity

{/* View Mode Switcher */}
{/* Regenerate Button */} {/* Summary Stats */}
✅ {data.summary.built} Built
⏳ {data.summary.missing} To Build
{/* Touchpoints View - What users see and engage with */} {viewMode === 'touchpoints' && (

Everything users see and engage with - screens, features, social posts, blogs, invites, and all customer-facing elements.

{data?.workItems.filter(item => isTouchpoint(item)).map((item, index) => ( { setExpandedItems(prev => { const newSet = new Set(prev); if (newSet.has(item.id)) { newSet.delete(item.id); } else { newSet.add(item.id); } return newSet; }); }} > ))}
Type Touchpoint Scope Design Code Assigned Sessions Commits Cost
{getWorkItemType(item)}
{item.status === 'built' ? ( ) : item.status === 'in_progress' ? ( ) : ( )}
{item.title}
{expandedItems.has(item.id) && (
{item.requirements.map((req) => (
{req.status === 'built' ? ( ) : ( )} {req.text}
))}
)}
{renderStatusBadge(getPhaseStatus(item.status, 'scope'))} {renderStatusBadge(getPhaseStatus(item.status, 'design'))} {renderStatusBadge(getPhaseStatus(item.status, 'code'))} {item.assigned || data?.projectCreator || 'You'} 0 ? 'text-blue-600 font-medium' : 'text-gray-400'}> {item.sessionsCount} 0 ? 'text-blue-600 font-medium' : 'text-gray-400'}> {item.commitsCount} {item.estimatedCost ? `$${item.estimatedCost.toFixed(2)}` : '-'}
)} {/* Journey View - Customer lifecycle stages */} {viewMode === 'journey' && (

Customer lifecycle journey from discovery to purchase - organizing all touchpoints and technical components by user stage.

{/* Journey Sections - Customer Lifecycle */} {['Discovery', 'Research', 'Onboarding', 'First Use', 'Active', 'Support', 'Purchase'].map(sectionName => { const sectionItems = data.workItems.filter(item => getJourneySection(item) === sectionName); if (sectionItems.length === 0) return null; const sectionStats = { done: sectionItems.filter(i => i.status === 'built').length, started: sectionItems.filter(i => i.status === 'in_progress').length, todo: sectionItems.filter(i => i.status === 'missing').length, total: sectionItems.length }; const isCollapsed = collapsedJourneySections.has(sectionName); return (
{/* Section Header */}
toggleJourneySection(sectionName)} >
{isCollapsed ? ( ) : ( )} {getJourneySectionIcon(sectionName)}

{sectionName}

{sectionStats.done}/{sectionStats.total} complete
{sectionStats.done > 0 && ( {sectionStats.done} done )} {sectionStats.started > 0 && ( {sectionStats.started} started )} {sectionStats.todo > 0 && ( {sectionStats.todo} to-do )}
{/* Section Items */} {!isCollapsed && (
{sectionItems.map(item => (
{ setExpandedItems(prev => { const newSet = new Set(prev); if (newSet.has(item.id)) { newSet.delete(item.id); } else { newSet.add(item.id); } return newSet; }); }} >
{/* Status Icon */} {item.status === 'built' ? ( ) : item.status === 'in_progress' ? ( ) : ( )}
{/* Title and Type */}
{item.title} {getWorkItemType(item)}
{/* Phase Status */}
Spec:{' '} {renderStatusBadge(getPhaseStatus(item.status, 'scope'))}
Design:{' '} {renderStatusBadge(getPhaseStatus(item.status, 'design'))}
Code:{' '} {renderStatusBadge(getPhaseStatus(item.status, 'code'))}
{/* Expanded Requirements */} {expandedItems.has(item.id) && (

Requirements:

{item.requirements.map((req) => (
{req.status === 'built' ? ( ) : ( )} {req.text}
))}
)}
{/* Right Side Stats */}
Sessions
0 ? 'text-blue-600 font-bold' : ''}>{item.sessionsCount}
Commits
0 ? 'text-blue-600 font-bold' : ''}>{item.commitsCount}
Cost
{item.estimatedCost ? `$${item.estimatedCost.toFixed(2)}` : '-'}
))}
)}
); })}
)} {/* Technical View - Infrastructure that powers everything */} {viewMode === 'technical' && (

Technical infrastructure that powers the product - APIs, backend services, authentication, and system integrations.

{data?.workItems.filter(item => isTechnical(item)).map((item, index) => ( { setExpandedItems(prev => { const newSet = new Set(prev); if (newSet.has(item.id)) { newSet.delete(item.id); } else { newSet.add(item.id); } return newSet; }); }} > ))}
Type Technical Component Scope Design Code Assigned Sessions Commits Cost
{getWorkItemType(item)}
{item.status === 'built' ? ( ) : item.status === 'in_progress' ? ( ) : ( )}
{item.title}
{expandedItems.has(item.id) && (
{item.requirements.map((req) => (
{req.status === 'built' ? ( ) : ( )} {req.text}
))}
)}
{renderStatusBadge(getPhaseStatus(item.status, 'scope'))} {renderStatusBadge(getPhaseStatus(item.status, 'design'))} {renderStatusBadge(getPhaseStatus(item.status, 'code'))} {item.assigned || data?.projectCreator || 'You'} 0 ? 'text-blue-600 font-medium' : 'text-gray-400'}> {item.sessionsCount} 0 ? 'text-blue-600 font-medium' : 'text-gray-400'}> {item.commitsCount} {item.estimatedCost ? `$${item.estimatedCost.toFixed(2)}` : '-'}
)}
{/* End Main Content */}
); }