mission-control/app/page.tsx
OpenClaw Bot 762c59500e Mission Control Phase 2: Transform Tasks page to overview
- Replaced kanban with task overview/summary view
- Added task stats cards (total, in progress, high priority, overdue)
- Added recent activity sections (updated, completed, high priority)
- Added quick action links to gantt-board
- Created lib/data/tasks.ts with data fetching functions
- Removed file-based storage (taskDb.ts, api/tasks/route.ts)
- Connected to gantt-board Supabase for real data
2026-02-21 22:48:15 -06:00

212 lines
8.4 KiB
TypeScript

import { DashboardLayout } from "@/components/layout/sidebar";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Activity, Calendar, CheckCircle2, Target, TrendingUp, Clock } from "lucide-react";
import { fetchDashboardStats } from "@/lib/data/stats";
// Force dynamic rendering to fetch fresh data from Supabase on each request
export const dynamic = "force-dynamic";
const MISSION_STATEMENT = "Build an iOS empire that generates the cashflow to retire on our own terms, travel the world with Heidi, honor every family milestone in style, and prove that 53 is just the launchpad to life's greatest chapter.";
export default async function DashboardPage() {
// Fetch real stats from Supabase
const stats = await fetchDashboardStats();
const kpiData = [
{
title: "Active Tasks",
value: String(stats.activeTasksCount),
change: `of ${stats.totalTasksCount} total tasks`,
icon: CheckCircle2,
trend: "up" as const,
},
{
title: "Goals Progress",
value: `${stats.goalsProgress}%`,
change: "based on completed tasks",
icon: Target,
trend: "up" as const,
},
{
title: "Apps Built",
value: String(stats.appsBuilt),
change: `${stats.projectsCount} total projects`,
icon: TrendingUp,
trend: "up" as const,
},
{
title: "Year Progress",
value: `${stats.yearProgress}%`,
change: `Day ${stats.yearDay} of ${stats.yearTotalDays}`,
icon: Clock,
trend: "neutral" as const,
},
];
const recentActivity = [
{ action: "Dashboard now uses live Supabase data", time: "Just now", type: "system" },
{ action: "Connected to gantt-board database", time: "Recently", type: "system" },
{ action: `${stats.activeTasksCount} active tasks tracked`, time: "Live", type: "task" },
{ action: `${stats.projectsCount} projects monitored`, time: "Live", type: "project" },
];
const upcomingEvents = [
{ title: "Yearly Anniversary", date: "Feb 23", type: "personal" },
{ title: "Grabbing Anderson's dogs", date: "Feb 26, 5:30 PM", type: "task" },
{ title: "Contract Renewal Check", date: "Mar 2026", type: "work" },
];
return (
<DashboardLayout>
<div className="space-y-8">
{/* Mission Statement Banner */}
<Card className="bg-gradient-to-r from-blue-600/20 via-purple-600/20 to-pink-600/20 border-blue-500/30">
<CardContent className="p-6">
<div className="flex items-start gap-4">
<div className="w-10 h-10 rounded-full bg-gradient-to-br from-blue-500 to-purple-600 flex items-center justify-center shrink-0">
<Target className="w-5 h-5 text-white" />
</div>
<div>
<h2 className="text-sm font-semibold text-muted-foreground uppercase tracking-wide mb-2">
The Mission
</h2>
<p className="text-lg font-medium leading-relaxed">
{MISSION_STATEMENT}
</p>
</div>
</div>
</CardContent>
</Card>
{/* Header */}
<div>
<h1 className="text-3xl font-bold tracking-tight">Dashboard</h1>
<p className="text-muted-foreground mt-1">
Welcome back, Matt. Here's your mission overview.
</p>
</div>
{/* KPI Cards */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
{kpiData.map((kpi) => {
const Icon = kpi.icon;
return (
<Card key={kpi.title}>
<CardHeader className="flex flex-row items-center justify-between pb-2">
<CardTitle className="text-sm font-medium text-muted-foreground">
{kpi.title}
</CardTitle>
<Icon className="w-4 h-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{kpi.value}</div>
<p className="text-xs text-muted-foreground mt-1">{kpi.change}</p>
</CardContent>
</Card>
);
})}
</div>
{/* Two Column Layout */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
{/* Recent Activity */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Activity className="w-5 h-5" />
Recent Activity
</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-4">
{recentActivity.map((item, i) => (
<div key={i} className="flex items-start gap-3 pb-3 border-b border-border last:border-0 last:pb-0">
<div className="w-2 h-2 rounded-full bg-primary mt-2" />
<div className="flex-1">
<p className="text-sm font-medium">{item.action}</p>
<p className="text-xs text-muted-foreground">{item.time}</p>
</div>
</div>
))}
</div>
</CardContent>
</Card>
{/* Upcoming Events */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Calendar className="w-5 h-5" />
Upcoming Events
</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-4">
{upcomingEvents.map((event, i) => (
<div key={i} className="flex items-start gap-3 pb-3 border-b border-border last:border-0 last:pb-0">
<div className="w-2 h-2 rounded-full bg-blue-500 mt-2" />
<div className="flex-1">
<p className="text-sm font-medium">{event.title}</p>
<p className="text-xs text-muted-foreground">{event.date}</p>
</div>
<span className="text-xs px-2 py-1 rounded-full bg-secondary text-secondary-foreground">
{event.type}
</span>
</div>
))}
</div>
</CardContent>
</Card>
</div>
{/* Mission Progress */}
<Card>
<CardHeader>
<CardTitle>Mission Progress</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-4">
<div>
<div className="flex justify-between text-sm mb-2">
<span>Goals Progress (Completed Tasks)</span>
<span className="text-muted-foreground">{stats.goalsProgress}% complete</span>
</div>
<div className="h-2 bg-secondary rounded-full overflow-hidden">
<div
className="h-full bg-gradient-to-r from-blue-500 to-purple-500 rounded-full transition-all duration-500"
style={{ width: `${stats.goalsProgress}%` }}
/>
</div>
</div>
<div>
<div className="flex justify-between text-sm mb-2">
<span>iOS Apps Portfolio</span>
<span className="text-muted-foreground">{stats.appsBuilt} apps built</span>
</div>
<div className="h-2 bg-secondary rounded-full overflow-hidden">
<div
className="h-full bg-gradient-to-r from-green-500 to-emerald-500 rounded-full transition-all duration-500"
style={{ width: `${Math.min(stats.appsBuilt * 10, 100)}%` }}
/>
</div>
</div>
<div>
<div className="flex justify-between text-sm mb-2">
<span>Year Progress</span>
<span className="text-muted-foreground">Day {stats.yearDay} of {stats.yearTotalDays}</span>
</div>
<div className="h-2 bg-secondary rounded-full overflow-hidden">
<div
className="h-full bg-gradient-to-r from-orange-500 to-red-500 rounded-full transition-all duration-500"
style={{ width: `${stats.yearProgress}%` }}
/>
</div>
</div>
</div>
</CardContent>
</Card>
</div>
</DashboardLayout>
);
}