'use client' import { useState, useEffect } from 'react' import { createClientLogger } from '@/lib/client-logger' const log = createClientLogger('StandupPanel') interface StandupReport { date: string generatedAt: string summary: { totalAgents: number totalCompleted: number totalInProgress: number totalAssigned: number totalReview: number totalBlocked: number totalActivity: number overdue: number } agentReports: Array<{ agent: { name: string role: string status: string last_seen?: number last_activity?: string } completedToday: Array<{ id: number title: string status: string updated_at: number }> inProgress: Array<{ id: number title: string status: string created_at: number due_date?: number }> assigned: Array<{ id: number title: string status: string created_at: number due_date?: number priority: string }> review: Array<{ id: number title: string status: string updated_at: number }> blocked: Array<{ id: number title: string status: string priority: string created_at: number metadata?: any }> activity: { actionCount: number commentsCount: number } }> teamAccomplishments: Array<{ id: number title: string agent: string updated_at: number }> teamBlockers: Array<{ id: number title: string priority: string agent: string created_at: number }> overdueTasks: Array<{ id: number title: string due_date: number status: string agent_name?: string }> } interface StandupHistory { id: number date: string generatedAt: string summary: any agentCount: number } export function StandupPanel() { const [standupReport, setStandupReport] = useState(null) const [standupHistory, setStandupHistory] = useState([]) const [loading, setLoading] = useState(false) const [error, setError] = useState(null) const [selectedDate, setSelectedDate] = useState(new Date().toISOString().split('T')[0]) const [view, setView] = useState<'current' | 'history'>('current') // Generate standup report const generateStandup = async (date?: string) => { try { setLoading(true) setError(null) const response = await fetch('/api/standup', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ date: date || selectedDate }) }) if (!response.ok) throw new Error('Failed to generate standup') const data = await response.json() setStandupReport(data.standup) } catch (err) { setError(err instanceof Error ? err.message : 'An error occurred') } finally { setLoading(false) } } // Fetch standup history const fetchHistory = async () => { try { const response = await fetch('/api/standup/history') if (!response.ok) throw new Error('Failed to fetch history') const data = await response.json() setStandupHistory(data.history || []) } catch (err) { log.error('Failed to fetch standup history:', err) } } useEffect(() => { if (view === 'history') { fetchHistory() } }, [view]) // Format date for display const formatDate = (dateStr: string) => { return new Date(dateStr).toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }) } // Format time for display const formatTime = (timestamp: number) => { return new Date(timestamp * 1000).toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' }) } // Get priority color const getPriorityColor = (priority: string) => { const colors: Record = { low: 'text-green-400', medium: 'text-yellow-400', high: 'text-orange-400', urgent: 'text-red-400' } return colors[priority] || 'text-muted-foreground' } // Export standup as text const exportStandup = () => { if (!standupReport) return const lines = [ `# Daily Standup - ${formatDate(standupReport.date)}`, `Generated: ${new Date(standupReport.generatedAt).toLocaleString()}`, '', '## Summary', `- **Agents Active:** ${standupReport.summary.totalAgents}`, `- **Completed Today:** ${standupReport.summary.totalCompleted}`, `- **In Progress:** ${standupReport.summary.totalInProgress}`, `- **Assigned:** ${standupReport.summary.totalAssigned}`, `- **In Review:** ${standupReport.summary.totalReview}`, `- **Blocked:** ${standupReport.summary.totalBlocked}`, `- **Overdue:** ${standupReport.summary.overdue}`, '', ] // Add team accomplishments if (standupReport.teamAccomplishments.length > 0) { lines.push('## Team Accomplishments') standupReport.teamAccomplishments.forEach(task => { lines.push(`- **${task.agent}**: ${task.title}`) }) lines.push('') } // Add team blockers if (standupReport.teamBlockers.length > 0) { lines.push('## Team Blockers') standupReport.teamBlockers.forEach(task => { lines.push(`- **${task.agent}** [${task.priority.toUpperCase()}]: ${task.title}`) }) lines.push('') } // Add individual agent reports lines.push('## Individual Reports') standupReport.agentReports.forEach(report => { lines.push(`### ${report.agent.name} (${report.agent.role})`) if (report.completedToday.length > 0) { lines.push('**Completed Today:**') report.completedToday.forEach(task => { lines.push(`- ${task.title}`) }) } if (report.inProgress.length > 0) { lines.push('**In Progress:**') report.inProgress.forEach(task => { lines.push(`- ${task.title}`) }) } if (report.blocked.length > 0) { lines.push('**Blocked:**') report.blocked.forEach(task => { lines.push(`- [${task.priority.toUpperCase()}] ${task.title}`) }) } lines.push('') }) const text = lines.join('\n') const blob = new Blob([text], { type: 'text/markdown' }) const url = URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = `standup-${standupReport.date}.md` document.body.appendChild(a) a.click() document.body.removeChild(a) URL.revokeObjectURL(url) } return (
{/* Header */}

Daily Standup

{/* View Toggle */}
{view === 'current' && ( <> setSelectedDate(e.target.value)} className="bg-surface-1 text-foreground rounded-md px-3 py-1.5 text-sm focus:outline-none focus:ring-1 focus:ring-primary/50 border border-border" /> {standupReport && ( )} )}
{/* Error Display */} {error && (
{error}
)} {/* Content */}
{view === 'current' ? ( // Current Standup View standupReport ? (
{/* Report Header */}

Standup for {formatDate(standupReport.date)}

Generated on {new Date(standupReport.generatedAt).toLocaleString()}

{/* Summary Stats */}
{standupReport.summary.totalCompleted}
Completed
{standupReport.summary.totalInProgress}
In Progress
{standupReport.summary.totalBlocked}
Blocked
{standupReport.summary.overdue}
Overdue
{/* Team Accomplishments */} {standupReport.teamAccomplishments.length > 0 && (

🎉 Team Accomplishments

{standupReport.teamAccomplishments.map(task => (
{task.title} {task.agent}
))}
)} {/* Team Blockers */} {standupReport.teamBlockers.length > 0 && (

🚫 Team Blockers

{standupReport.teamBlockers.map(task => (
{task.title} [{task.priority.toUpperCase()}]
{task.agent}
))}
)} {/* Overdue Tasks */} {standupReport.overdueTasks.length > 0 && (

⏰ Overdue Tasks

{standupReport.overdueTasks.map(task => (
{task.title} (Due: {new Date(task.due_date * 1000).toLocaleDateString()})
{task.agent_name || 'Unassigned'}
))}
)} {/* Individual Agent Reports */}

👥 Individual Reports

{standupReport.agentReports.map(report => (
{report.agent.name}

{report.agent.role}

Activity: {report.activity.actionCount} actions, {report.activity.commentsCount} comments
{report.agent.last_activity && (
{report.agent.last_activity}
)}
{/* Completed Today */}
✅ Completed ({report.completedToday.length})
{report.completedToday.map(task => (
{task.title}
))} {report.completedToday.length === 0 && (
None
)}
{/* In Progress */}
🔄 In Progress ({report.inProgress.length})
{report.inProgress.map(task => (
{task.title}
))} {report.inProgress.length === 0 && (
None
)}
{/* Assigned */}
📋 Assigned ({report.assigned.length})
{report.assigned.map(task => (
{task.title}
[{task.priority}]
))} {report.assigned.length === 0 && (
None
)}
{/* Blocked */}
🚫 Blocked ({report.blocked.length})
{report.blocked.map(task => (
{task.title}
[{task.priority}]
))} {report.blocked.length === 0 && (
None
)}
))}
) : ( // Empty state for current view

No Standup Generated

Select a date and generate a report

) ) : ( // History View
{standupHistory.length === 0 ? (

No standup history found

) : (
{standupHistory.map(history => (

{formatDate(history.date)}

Generated: {new Date(history.generatedAt).toLocaleString()}

{history.agentCount} agents participated

{history.summary && (
Completed: {history.summary.completed || 0}
In Progress: {history.summary.inProgress || 0}
Blocked: {history.summary.blocked || 0}
)}
))}
)}
)}
) }