import { StatusCard } from "./StatusCard"; import { RecentActivity } from "./RecentActivity"; import { RepositoryList } from "./RepositoryList"; import { GitFork, Clock, FlipHorizontal, Building2 } from "lucide-react"; import { useCallback, useEffect, useState } from "react"; import type { MirrorJob, Organization, Repository } from "@/lib/db/schema"; import { useAuth } from "@/hooks/useAuth"; import { apiRequest } from "@/lib/utils"; import type { DashboardApiResponse } from "@/types/dashboard"; import { useSSE } from "@/hooks/useSEE"; import { toast } from "sonner"; import { Skeleton } from "@/components/ui/skeleton"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; export function Dashboard() { const { user } = useAuth(); const [repositories, setRepositories] = useState([]); const [organizations, setOrganizations] = useState([]); const [activities, setActivities] = useState([]); const [isLoading, setIsLoading] = useState(true); const [repoCount, setRepoCount] = useState(0); const [orgCount, setOrgCount] = useState(0); const [mirroredCount, setMirroredCount] = useState(0); const [lastSync, setLastSync] = useState(null); // Create a stable callback using useCallback const handleNewMessage = useCallback((data: MirrorJob) => { if (data.repositoryId) { setRepositories((prevRepos) => prevRepos.map((repo) => repo.id === data.repositoryId ? { ...repo, status: data.status, details: data.details } : repo ) ); } else if (data.organizationId) { setOrganizations((prevOrgs) => prevOrgs.map((org) => org.id === data.organizationId ? { ...org, status: data.status, details: data.details } : org ) ); } setActivities((prevActivities) => [data, ...prevActivities]); console.log("Received new log:", data); }, []); // Use the SSE hook const { connected } = useSSE({ userId: user?.id, onMessage: handleNewMessage, }); useEffect(() => { const fetchDashboardData = async () => { try { if (!user || !user.id) { return; } const response = await apiRequest( `/dashboard?userId=${user.id}`, { method: "GET", } ); if (response.success) { setRepositories(response.repositories); setOrganizations(response.organizations); setActivities(response.activities); setRepoCount(response.repoCount); setOrgCount(response.orgCount); setMirroredCount(response.mirroredCount); setLastSync(response.lastSync); } else { toast.error(response.error || "Error fetching dashboard data"); } } catch (error) { toast.error( error instanceof Error ? error.message : "Error fetching dashboard data" ); } finally { setIsLoading(false); } }; fetchDashboardData(); }, [user]); // Status Card Skeleton component function StatusCardSkeleton() { return ( ); } return isLoading || !connected ? (
{/* Repository List Skeleton */}
{Array.from({ length: 3 }).map((_, i) => ( ))}
{/* Recent Activity Skeleton */}
{Array.from({ length: 3 }).map((_, i) => ( ))}
) : (
} description="Repositories being mirrored" /> } description="Successfully mirrored" /> } description="GitHub organizations" /> } description="Last successful sync" />
{/* the api already sends 10 activities only but slicing in case of realtime updates */}
); }