holy fkn airball
This commit is contained in:
@@ -1,40 +1,149 @@
|
||||
import AnalyticsDashboard from "@/components/analytics/AnalyticsDashboard";
|
||||
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';
|
||||
|
||||
interface AnalyticsOverview {
|
||||
orders: {
|
||||
total: number;
|
||||
completed: number;
|
||||
pending: number;
|
||||
completionRate: string;
|
||||
};
|
||||
revenue: {
|
||||
total: number;
|
||||
monthly: number;
|
||||
weekly: number;
|
||||
averageOrderValue: number;
|
||||
};
|
||||
products: {
|
||||
total: number;
|
||||
};
|
||||
customers: {
|
||||
unique: number;
|
||||
};
|
||||
// Vendor type for consistency
|
||||
interface Vendor {
|
||||
_id: string;
|
||||
username: string;
|
||||
storeId: string;
|
||||
pgpKey: string;
|
||||
__v: number;
|
||||
}
|
||||
|
||||
export default async function AnalyticsPage() {
|
||||
const analyticsData = await fetchServer<AnalyticsOverview>("/analytics/overview");
|
||||
interface User {
|
||||
vendor: Vendor;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold text-foreground">Analytics Dashboard</h1>
|
||||
<p className="text-muted-foreground mt-2">
|
||||
Comprehensive insights into your store performance, sales trends, and customer behavior.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<AnalyticsDashboard initialData={analyticsData} />
|
||||
</div>
|
||||
);
|
||||
export default async function AnalyticsPage({
|
||||
searchParams,
|
||||
}: {
|
||||
searchParams: { storeId?: string };
|
||||
}) {
|
||||
const startTime = performance.now();
|
||||
|
||||
// Check for storeId in query parameters (for staff users)
|
||||
const storeId = searchParams.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>
|
||||
|
||||
{/* Footer with version info */}
|
||||
<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>
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user