Some checks failed
Build Frontend / build (push) Failing after 7s
Replaces imports from 'components/ui' with 'components/common' across the app and dashboard pages, and updates model and API imports to use new paths under 'lib'. Removes redundant authentication checks from several dashboard pages. Adds new dashboard components and utility files, and reorganizes hooks and services into the 'lib' directory for improved structure.
187 lines
6.0 KiB
TypeScript
187 lines
6.0 KiB
TypeScript
import Dashboard from "@/components/dashboard/dashboard";
|
|
import { fetchServer } from '@/lib/api';
|
|
import { performance } from 'perf_hooks';
|
|
import { Info, GitCommit, User, Zap } from 'lucide-react';
|
|
import packageJson from '../../package.json';
|
|
import { getGitInfo, getShortGitHash } from '@/lib/utils/git';
|
|
import { Suspense } from 'react';
|
|
import dynamic from 'next/dynamic';
|
|
import { Skeleton } from '@/components/common/skeleton';
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/common/card';
|
|
import DashboardContentWrapper from './dashboard-content-wrapper';
|
|
|
|
// Loading skeleton for the dashboard content
|
|
function DashboardContentSkeleton() {
|
|
return (
|
|
<div
|
|
className="space-y-6 animate-in fade-in duration-500 relative"
|
|
role="status"
|
|
aria-label="Loading dashboard content"
|
|
aria-live="polite"
|
|
>
|
|
{/* Subtle loading indicator */}
|
|
<div className="absolute top-0 left-0 right-0 h-1 bg-muted overflow-hidden rounded-full">
|
|
<div className="h-full bg-primary w-1/3"
|
|
style={{
|
|
background: 'linear-gradient(90deg, transparent, hsl(var(--primary)), transparent)',
|
|
backgroundSize: '200% 100%',
|
|
animation: 'shimmer 2s ease-in-out infinite',
|
|
}}
|
|
/>
|
|
</div>
|
|
|
|
{/* Header skeleton */}
|
|
<div>
|
|
<Skeleton className="h-8 w-64 mb-2" />
|
|
<Skeleton className="h-4 w-96 max-w-full" />
|
|
</div>
|
|
|
|
{/* Stats cards skeleton */}
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 lg:gap-6">
|
|
{[...Array(4)].map((_, i) => (
|
|
<Card
|
|
key={i}
|
|
className="animate-in fade-in slide-in-from-bottom-4"
|
|
style={{
|
|
animationDelay: `${i * 75}ms`,
|
|
animationDuration: '400ms',
|
|
animationFillMode: 'both',
|
|
}}
|
|
>
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
<Skeleton className="h-4 w-20" />
|
|
<Skeleton className="h-5 w-5 rounded" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<Skeleton className="h-7 w-16 mb-1" />
|
|
<Skeleton className="h-3 w-24" />
|
|
</CardContent>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
|
|
{/* Best selling products skeleton */}
|
|
<Card className="animate-in fade-in slide-in-from-bottom-4"
|
|
style={{
|
|
animationDelay: '300ms',
|
|
animationDuration: '400ms',
|
|
animationFillMode: 'both',
|
|
}}
|
|
>
|
|
<CardHeader>
|
|
<Skeleton className="h-6 w-48" />
|
|
<Skeleton className="h-4 w-72 max-w-full" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-4">
|
|
{[...Array(5)].map((_, i) => (
|
|
<div
|
|
key={i}
|
|
className="flex items-center gap-4 animate-in fade-in"
|
|
style={{
|
|
animationDelay: `${400 + i * 50}ms`,
|
|
animationDuration: '300ms',
|
|
animationFillMode: 'both',
|
|
}}
|
|
>
|
|
<Skeleton className="h-12 w-12 rounded-md" />
|
|
<div className="space-y-2">
|
|
<Skeleton className="h-4 w-40" />
|
|
<Skeleton className="h-4 w-20" />
|
|
</div>
|
|
<div className="ml-auto text-right">
|
|
<Skeleton className="h-4 w-16 ml-auto" />
|
|
<Skeleton className="h-4 w-16 ml-auto mt-2" />
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Lazy load the Content component with error handling
|
|
const Content = dynamic(() => import("@/components/dashboard/content").catch((err) => {
|
|
console.error("Failed to load dashboard content:", err);
|
|
throw err;
|
|
}), {
|
|
loading: () => <DashboardContentSkeleton />
|
|
});
|
|
|
|
// ✅ Corrected Vendor Type
|
|
interface Vendor {
|
|
_id: string;
|
|
username: string;
|
|
storeId: string;
|
|
pgpKey: string;
|
|
__v: number;
|
|
}
|
|
|
|
interface User {
|
|
vendor: Vendor;
|
|
}
|
|
|
|
interface OrderStats {
|
|
totalOrders: number;
|
|
pendingOrders: number;
|
|
completedOrders: number;
|
|
cancelledOrders: number;
|
|
}
|
|
|
|
export default async function DashboardPage() {
|
|
const startTime = performance.now();
|
|
|
|
const [userResponse, orderStats] = await Promise.all([
|
|
fetchServer<User>("/auth/me"),
|
|
fetchServer<OrderStats>("/orders/stats")
|
|
]);
|
|
|
|
// Get git info using the new utility
|
|
const gitInfo = getGitInfo();
|
|
|
|
const endTime = performance.now();
|
|
const generationTime = (endTime - startTime).toFixed(2);
|
|
const panelVersion = packageJson.version;
|
|
const commitHash = gitInfo.hash;
|
|
|
|
const vendor = userResponse.vendor;
|
|
|
|
return (
|
|
<Dashboard>
|
|
<DashboardContentWrapper>
|
|
<Suspense fallback={<DashboardContentSkeleton />}>
|
|
<Content username={vendor.username} orderStats={orderStats} />
|
|
</Suspense>
|
|
</DashboardContentWrapper>
|
|
<div className="fixed bottom-2 right-2 text-xs text-muted-foreground bg-background/80 backdrop-blur-sm px-2 py-1 rounded border border-border/50 z-50 flex items-center space-x-2">
|
|
<div className="flex items-center gap-1">
|
|
<Info size={12} className="text-muted-foreground/80" />
|
|
<span>v{panelVersion}</span>
|
|
</div>
|
|
|
|
<div className="flex items-center gap-1">
|
|
<User size={12} className="text-muted-foreground/80" />
|
|
<span>{vendor.username}</span>
|
|
</div>
|
|
|
|
<div className="flex items-center gap-1">
|
|
<GitCommit size={12} className="text-muted-foreground/80" />
|
|
<span>{commitHash}</span>
|
|
</div>
|
|
|
|
<div className="flex items-center gap-1">
|
|
<Zap size={12} className="text-amber-500" />
|
|
<span>Generated in {generationTime}ms</span>
|
|
</div>
|
|
|
|
<span className="px-1.5 py-0.5 text-xs rounded-sm bg-emerald-500/20 text-emerald-300">
|
|
{process.env.NODE_ENV || 'development'}
|
|
</span>
|
|
</div>
|
|
</Dashboard>
|
|
);
|
|
}
|
|
|