Introduces an admin-only OrderDetailsModal component for viewing and managing order details, including status updates and transaction info. Updates OrdersTable to support the modal, and enhances the admin dashboard page with lazy loading and skeletons for better UX. Also fixes API client base URL handling for /api prefix.
99 lines
3.2 KiB
TypeScript
99 lines
3.2 KiB
TypeScript
"use client";
|
|
export const dynamic = "force-dynamic";
|
|
|
|
import React, { Suspense, lazy, useState } from "react";
|
|
import { Button } from "@/components/ui/button";
|
|
import Link from "next/link";
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
|
import { Skeleton } from "@/components/ui/skeleton";
|
|
import { Card, CardContent, CardHeader } from "@/components/ui/card";
|
|
|
|
// Lazy load admin components
|
|
const AdminAnalytics = lazy(() => import("@/components/admin/AdminAnalytics"));
|
|
const InviteVendorCard = lazy(() => import("@/components/admin/InviteVendorCard"));
|
|
const BanUserCard = lazy(() => import("@/components/admin/BanUserCard"));
|
|
const InvitationsListCard = lazy(() => import("@/components/admin/InvitationsListCard"));
|
|
const VendorsCard = lazy(() => import("@/components/admin/VendorsCard"));
|
|
|
|
// Loading skeleton for admin components
|
|
function AdminComponentSkeleton() {
|
|
return (
|
|
<div className="space-y-4">
|
|
<Card>
|
|
<CardHeader>
|
|
<Skeleton className="h-6 w-48" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-2">
|
|
<Skeleton className="h-4 w-full" />
|
|
<Skeleton className="h-4 w-3/4" />
|
|
<Skeleton className="h-4 w-1/2" />
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Loading skeleton for management cards
|
|
function ManagementCardsSkeleton() {
|
|
return (
|
|
<div className="grid gap-4 lg:gap-6 sm:grid-cols-2 lg:grid-cols-3 items-stretch">
|
|
{[1, 2, 3, 4].map((i) => (
|
|
<Card key={i}>
|
|
<CardHeader>
|
|
<Skeleton className="h-6 w-32" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<Skeleton className="h-20 w-full" />
|
|
</CardContent>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default function AdminPage() {
|
|
const [activeTab, setActiveTab] = useState("analytics");
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<h1 className="text-2xl font-semibold tracking-tight">Admin Dashboard</h1>
|
|
<p className="text-sm text-muted-foreground mt-1">Platform analytics and vendor management</p>
|
|
</div>
|
|
<Button asChild variant="outline" size="sm">
|
|
<Link href="/dashboard">Back to Dashboard</Link>
|
|
</Button>
|
|
</div>
|
|
|
|
<Tabs value={activeTab} onValueChange={setActiveTab} className="space-y-6">
|
|
<TabsList>
|
|
<TabsTrigger value="analytics">Analytics</TabsTrigger>
|
|
<TabsTrigger value="management">Management</TabsTrigger>
|
|
</TabsList>
|
|
|
|
<TabsContent value="analytics" className="space-y-6">
|
|
<Suspense fallback={<AdminComponentSkeleton />}>
|
|
<AdminAnalytics />
|
|
</Suspense>
|
|
</TabsContent>
|
|
|
|
<TabsContent value="management" className="space-y-6">
|
|
<Suspense fallback={<ManagementCardsSkeleton />}>
|
|
<div className="grid gap-4 lg:gap-6 sm:grid-cols-2 lg:grid-cols-3 items-stretch">
|
|
<VendorsCard />
|
|
<InviteVendorCard />
|
|
<BanUserCard />
|
|
<InvitationsListCard />
|
|
</div>
|
|
</Suspense>
|
|
</TabsContent>
|
|
</Tabs>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
|