Files
Sankofa/src/components/infrastructure/DocsDashboard.tsx

189 lines
6.3 KiB
TypeScript

'use client'
import { useState } from 'react'
import { useInfrastructureSummary } from '@/lib/hooks/useInfrastructureData'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { Button } from '@/components/ui/button'
import { GlobalSearch } from './GlobalSearch'
import Link from 'next/link'
import { Network, Shield, Calendar, DollarSign, Search } from 'lucide-react'
export function DocsDashboard() {
const { summary, loading, error } = useInfrastructureSummary()
const [searchOpen, setSearchOpen] = useState(false)
const cards = [
{
title: 'Network Topology',
description: 'View and edit regional network topology diagrams',
icon: Network,
href: '/infrastructure/docs/topology',
color: 'text-blue-400',
bgColor: 'bg-blue-500/10',
stats: summary
? {
label: 'Regions',
value: summary.totalRegions,
}
: null,
},
{
title: 'Compliance Mapping',
description: 'Track compliance requirements by country and region',
icon: Shield,
href: '/infrastructure/docs/compliance',
color: 'text-green-400',
bgColor: 'bg-green-500/10',
stats: summary
? {
label: 'Countries',
value: summary.totalCountries,
}
: null,
},
{
title: 'Deployment Timeline',
description: 'Manage infrastructure deployment milestones and schedules',
icon: Calendar,
href: '/infrastructure/docs/timeline',
color: 'text-purple-400',
bgColor: 'bg-purple-500/10',
stats: summary
? {
label: 'In Progress',
value: summary.deploymentProgress.inProgress,
}
: null,
},
{
title: 'Cost Estimates',
description: 'View and manage cost estimates by region and category',
icon: DollarSign,
href: '/infrastructure/docs/costs',
color: 'text-yellow-400',
bgColor: 'bg-yellow-500/10',
stats: summary
? {
label: 'Total Annual',
value: `$${(summary.totalCost / 1000000).toFixed(1)}M`,
}
: null,
},
]
if (loading) {
return (
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-4">
{cards.map((card) => (
<Card key={card.title} className="animate-pulse">
<CardHeader>
<div className="h-6 w-32 bg-studio-medium rounded" />
<div className="h-4 w-48 bg-studio-medium rounded mt-2" />
</CardHeader>
<CardContent>
<div className="h-8 w-16 bg-studio-medium rounded" />
</CardContent>
</Card>
))}
</div>
)
}
if (error) {
return (
<Card>
<CardHeader>
<CardTitle>Error Loading Dashboard</CardTitle>
<CardDescription>{error.message}</CardDescription>
</CardHeader>
</Card>
)
}
return (
<div className="space-y-6">
<div className="flex items-center justify-between">
<div>
<h1 className="text-3xl font-bold text-studio-light">Infrastructure Documentation</h1>
<p className="text-studio-medium mt-2">
Manage network topology, compliance, deployment timelines, and cost estimates
</p>
</div>
<Button variant="outline" onClick={() => setSearchOpen(true)}>
<Search className="h-4 w-4 mr-2" />
Search
</Button>
</div>
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-4">
{cards.map((card) => {
const Icon = card.icon
return (
<Link key={card.title} href={card.href} className="block">
<Card className="hover:border-studio-light transition-colors cursor-pointer h-full">
<CardHeader>
<div className="flex items-center justify-between">
<Icon className={`h-8 w-8 ${card.color}`} />
<div className={`h-12 w-12 rounded-lg ${card.bgColor} flex items-center justify-center`}>
<Icon className={`h-6 w-6 ${card.color}`} />
</div>
</div>
<CardTitle className="mt-4">{card.title}</CardTitle>
<CardDescription>{card.description}</CardDescription>
</CardHeader>
{card.stats && (
<CardContent>
<div className="mt-4">
<div className="text-2xl font-bold text-studio-light">{card.stats.value}</div>
<div className="text-sm text-studio-medium">{card.stats.label}</div>
</div>
</CardContent>
)}
</Card>
</Link>
)
})}
</div>
{summary && (
<div className="grid gap-6 md:grid-cols-3">
<Card>
<CardHeader>
<CardTitle>Deployment Progress</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-2">
<div className="flex justify-between">
<span className="text-studio-medium">Planned</span>
<span className="font-semibold">{summary.deploymentProgress.planned}</span>
</div>
<div className="flex justify-between">
<span className="text-studio-medium">In Progress</span>
<span className="font-semibold text-yellow-400">
{summary.deploymentProgress.inProgress}
</span>
</div>
<div className="flex justify-between">
<span className="text-studio-medium">Complete</span>
<span className="font-semibold text-green-400">
{summary.deploymentProgress.complete}
</span>
</div>
<div className="flex justify-between">
<span className="text-studio-medium">Blocked</span>
<span className="font-semibold text-red-400">
{summary.deploymentProgress.blocked}
</span>
</div>
</div>
</CardContent>
</Card>
</div>
)}
<GlobalSearch open={searchOpen} onOpenChange={setSearchOpen} />
</div>
)
}