151 lines
5.1 KiB
TypeScript
151 lines
5.1 KiB
TypeScript
import { Suspense } from 'react';
|
|
import { cookies } from 'next/headers';
|
|
import { redirect } from 'next/navigation';
|
|
import Dashboard from "@/components/dashboard/dashboard";
|
|
import AnalyticsDashboard from '@/components/analytics/AnalyticsDashboard';
|
|
import StoreSelector from '@/components/analytics/StoreSelector';
|
|
import { getAnalyticsOverviewServer } from '@/lib/server-api';
|
|
import { fetchServer } from '@/lib/api';
|
|
import { performance } from 'perf_hooks';
|
|
import { Info, GitCommit, User, Zap, BarChart3 } from 'lucide-react';
|
|
import packageJson from '../../../package.json';
|
|
import { getGitInfo } from '@/lib/utils/git';
|
|
|
|
// Vendor type for consistency
|
|
interface Vendor {
|
|
_id: string;
|
|
username: string;
|
|
storeId: string;
|
|
pgpKey: string;
|
|
__v: number;
|
|
}
|
|
|
|
interface User {
|
|
vendor: Vendor;
|
|
}
|
|
|
|
export default async function AnalyticsPage({
|
|
searchParams,
|
|
}: {
|
|
searchParams: Promise<{ storeId?: string }>;
|
|
}) {
|
|
const startTime = performance.now();
|
|
|
|
// Await searchParams as required by Next.js 15+
|
|
const resolvedSearchParams = await searchParams;
|
|
|
|
// Check for storeId in query parameters (for staff users)
|
|
const storeId = resolvedSearchParams?.storeId;
|
|
|
|
// Check for storeId in cookies (alternative method for staff users)
|
|
const cookieStore = await cookies();
|
|
const cookieStoreId = cookieStore.get('storeId')?.value;
|
|
|
|
// Use query parameter first, then cookie, then undefined (for vendors)
|
|
const finalStoreId = storeId || cookieStoreId;
|
|
|
|
try {
|
|
// Fetch user data and analytics data in parallel
|
|
const [userResponse, initialData] = await Promise.all([
|
|
fetchServer<User>("/auth/me"),
|
|
getAnalyticsOverviewServer(finalStoreId)
|
|
]);
|
|
|
|
// Get git info using the 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>
|
|
<div className="space-y-6">
|
|
{/* Analytics Content */}
|
|
<Suspense fallback={
|
|
<div className="flex items-center justify-center h-64">
|
|
<div className="text-center">
|
|
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary mx-auto mb-4"></div>
|
|
<p className="text-muted-foreground">Loading analytics...</p>
|
|
</div>
|
|
</div>
|
|
}>
|
|
<AnalyticsDashboard initialData={initialData} />
|
|
</Suspense>
|
|
</div>
|
|
|
|
<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>
|
|
);
|
|
} catch (error) {
|
|
console.error('Error fetching analytics data:', error);
|
|
|
|
// If it's a 401/403 error, redirect to login
|
|
if (error instanceof Error && error.message.includes('401')) {
|
|
redirect('/login');
|
|
}
|
|
|
|
// If it's a 400 error (missing storeId for staff), show store selector
|
|
if (error instanceof Error && error.message.includes('400')) {
|
|
return (
|
|
<Dashboard>
|
|
<div className="space-y-6">
|
|
<div className="text-center mb-8">
|
|
<h1 className="text-3xl font-bold text-foreground mb-4">Analytics Dashboard</h1>
|
|
<p className="text-muted-foreground">
|
|
Please select a store to view analytics data.
|
|
</p>
|
|
</div>
|
|
<StoreSelector />
|
|
</div>
|
|
</Dashboard>
|
|
);
|
|
}
|
|
|
|
// For other errors, show a fallback
|
|
return (
|
|
<Dashboard>
|
|
<div className="space-y-6">
|
|
<div className="text-center py-8">
|
|
<h1 className="text-3xl font-bold text-foreground mb-4">Analytics Dashboard</h1>
|
|
<p className="text-muted-foreground">
|
|
Unable to load analytics data. Please try refreshing the page.
|
|
</p>
|
|
{finalStoreId && (
|
|
<p className="text-sm text-muted-foreground mt-2">
|
|
Accessing store: {finalStoreId}
|
|
</p>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</Dashboard>
|
|
);
|
|
}
|
|
}
|