Add dashboard navigation and request timeouts
Added 'Back to Dashboard' buttons to all admin dashboard pages for improved navigation. Introduced AbortSignal timeouts to API client and middleware requests to prevent hanging network calls. Also enabled messaging customers from the order details page if Telegram info is available.
This commit is contained in:
@@ -5,6 +5,7 @@ import { Button } from "@/components/ui/button";
|
||||
import { Alert, AlertDescription } from "@/components/ui/alert";
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
|
||||
import { AlertTriangle, CheckCircle, XCircle, Clock, Bell, Shield } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function AdminAlertsPage() {
|
||||
// Mock data for system alerts
|
||||
@@ -93,10 +94,15 @@ export default function AdminAlertsPage() {
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-2xl font-semibold tracking-tight">System Alerts</h1>
|
||||
<p className="text-sm text-muted-foreground mt-1">Monitor system alerts and security notifications</p>
|
||||
</div>
|
||||
<Button asChild variant="outline" size="sm">
|
||||
<Link href="/dashboard">Back to Dashboard</Link>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Alert Summary */}
|
||||
<div className="grid gap-4 md:grid-cols-4">
|
||||
|
||||
@@ -12,6 +12,7 @@ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@
|
||||
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from "@/components/ui/alert-dialog";
|
||||
import { UserX, Shield, Search, Ban, Unlock } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function AdminBanPage() {
|
||||
const [banData, setBanData] = useState({
|
||||
@@ -62,10 +63,15 @@ export default function AdminBanPage() {
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-2xl font-semibold tracking-tight">Ban Users</h1>
|
||||
<p className="text-sm text-muted-foreground mt-1">Manage user bans and suspensions</p>
|
||||
</div>
|
||||
<Button asChild variant="outline" size="sm">
|
||||
<Link href="/dashboard">Back to Dashboard</Link>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Stats Cards */}
|
||||
<div className="grid gap-4 md:grid-cols-4">
|
||||
|
||||
@@ -10,6 +10,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { UserPlus, Mail, Copy, Check } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function AdminInvitePage() {
|
||||
const [inviteData, setInviteData] = useState({
|
||||
@@ -35,10 +36,15 @@ export default function AdminInvitePage() {
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-2xl font-semibold tracking-tight">Invite Vendor</h1>
|
||||
<p className="text-sm text-muted-foreground mt-1">Send invitations to new vendors to join the platform</p>
|
||||
</div>
|
||||
<Button asChild variant="outline" size="sm">
|
||||
<Link href="/dashboard">Back to Dashboard</Link>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-6 lg:grid-cols-2">
|
||||
{/* Invite Form */}
|
||||
|
||||
@@ -7,14 +7,21 @@ import RecentOrdersCard from "@/components/admin/RecentOrdersCard";
|
||||
import SystemStatusCard from "@/components/admin/SystemStatusCard";
|
||||
import InvitationsListCard from "@/components/admin/InvitationsListCard";
|
||||
import VendorsCard from "@/components/admin/VendorsCard";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function AdminPage() {
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-2xl font-semibold tracking-tight">Admin</h1>
|
||||
<p className="text-sm text-muted-foreground mt-1">Restricted area. Only admin1 can access.</p>
|
||||
</div>
|
||||
<Button asChild variant="outline" size="sm">
|
||||
<Link href="/dashboard">Back to Dashboard</Link>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-4 lg:gap-6 sm:grid-cols-2 lg:grid-cols-3 items-stretch">
|
||||
<SystemStatusCard />
|
||||
|
||||
@@ -8,14 +8,20 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { Settings, Shield, Bell, Database, Globe, Key, Save } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function AdminSettingsPage() {
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-2xl font-semibold tracking-tight">Admin Settings</h1>
|
||||
<p className="text-sm text-muted-foreground mt-1">Configure system settings and preferences</p>
|
||||
</div>
|
||||
<Button asChild variant="outline" size="sm">
|
||||
<Link href="/dashboard">Back to Dashboard</Link>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-6 lg:grid-cols-2">
|
||||
{/* General Settings */}
|
||||
|
||||
@@ -22,7 +22,8 @@ import {
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
import { Clipboard, Truck, Package, ArrowRight, ChevronDown, AlertTriangle, Copy, Loader2, RefreshCw } from "lucide-react";
|
||||
import { Clipboard, Truck, Package, ArrowRight, ChevronDown, AlertTriangle, Copy, Loader2, RefreshCw, MessageCircle } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
@@ -829,6 +830,22 @@ export default function OrderDetailsPage() {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{(order?.telegramBuyerId || order?.telegramUsername) && (
|
||||
<div className="pt-2">
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
asChild
|
||||
>
|
||||
<Link href={`/dashboard/chats/new?buyerId=${order?.telegramBuyerId || order?.telegramUsername}`}
|
||||
title={`Chat with customer${order?.telegramUsername ? ` @${order.telegramUsername}` : ''}`}
|
||||
>
|
||||
<MessageCircle className="h-4 w-4 mr-2" />
|
||||
Message customer
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@@ -232,7 +232,8 @@ export async function clientFetch<T = any>(url: string, options: RequestInit = {
|
||||
headers,
|
||||
credentials: 'include',
|
||||
mode: 'cors',
|
||||
referrerPolicy: 'strict-origin-when-cross-origin'
|
||||
referrerPolicy: 'strict-origin-when-cross-origin',
|
||||
signal: AbortSignal.timeout(30000), // 30 second timeout
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
@@ -303,6 +304,7 @@ export async function fetchClient<T>(
|
||||
method,
|
||||
credentials: 'include',
|
||||
headers: requestHeaders,
|
||||
signal: AbortSignal.timeout(30000), // 30 second timeout
|
||||
...rest,
|
||||
};
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ export async function middleware(req: NextRequest) {
|
||||
method: "GET",
|
||||
headers,
|
||||
credentials: 'include',
|
||||
signal: AbortSignal.timeout(10000), // 10 second timeout
|
||||
});
|
||||
|
||||
console.log(`Middleware: Auth check responded with status ${res.status}`);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"commitHash": "1fc29e6",
|
||||
"buildTime": "2025-10-23T20:42:39.661Z"
|
||||
"commitHash": "fcba1a8",
|
||||
"buildTime": "2025-10-30T01:13:38.854Z"
|
||||
}
|
||||
Reference in New Issue
Block a user