"use client"; import React, { useState, useEffect, useCallback } from "react"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { Search, MoreHorizontal, UserCheck, UserX, Mail, Loader2, Store, Shield, ShieldAlert, Clock, Calendar, Pencil, Plus } from "lucide-react"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import { Label } from "@/components/ui/label"; import { fetchClient } from "@/lib/api-client"; import { useToast } from "@/hooks/use-toast"; import { motion, AnimatePresence } from "framer-motion"; interface Vendor { _id: string; username: string; storeId?: string; createdAt?: string; lastLogin?: string; isAdmin?: boolean; isActive: boolean; } interface PaginationResponse { success: boolean; vendors: Vendor[]; pagination: { page: number; limit: number; total: number; totalPages: number; hasNextPage: boolean; hasPrevPage: boolean; }; } export default function AdminVendorsPage() { const { toast } = useToast(); const [loading, setLoading] = useState(true); const [vendors, setVendors] = useState([]); const [page, setPage] = useState(1); const [pagination, setPagination] = useState(null); const [searchQuery, setSearchQuery] = useState(""); const [isEditStoreOpen, setIsEditStoreOpen] = useState(false); const [editingVendor, setEditingVendor] = useState(null); const [newStoreId, setNewStoreId] = useState(""); const [updating, setUpdating] = useState(false); const handleEditStore = (vendor: Vendor) => { setEditingVendor(vendor); setNewStoreId(vendor.storeId || ""); setIsEditStoreOpen(true); }; const saveStoreId = async () => { if (!editingVendor) return; try { setUpdating(true); await fetchClient(`/admin/vendors/${editingVendor._id}/store-id`, { method: 'PUT', body: JSON.stringify({ storeId: newStoreId }) }); toast({ title: "Success", description: "Store ID updated successfully", }); setIsEditStoreOpen(false); fetchVendors(); // Refresh list } catch (error: any) { toast({ title: "Error", description: error.message || "Failed to update store ID", variant: "destructive", }); } finally { setUpdating(false); } }; const fetchVendors = useCallback(async () => { try { setLoading(true); const params = new URLSearchParams({ page: page.toString(), limit: '25' }); const data = await fetchClient(`/admin/vendors?${params.toString()}`); setVendors(data.vendors); setPagination(data.pagination); } catch (error: any) { console.error("Failed to fetch vendors:", error); toast({ title: "Error", description: error.message || "Failed to load vendors", variant: "destructive", }); } finally { setLoading(false); } }, [page, toast]); useEffect(() => { fetchVendors(); }, [fetchVendors]); const filteredVendors = searchQuery.trim() ? vendors.filter(v => v.username.toLowerCase().includes(searchQuery.toLowerCase()) || (v.storeId && v.storeId.toString().toLowerCase().includes(searchQuery.toLowerCase())) ) : vendors; const activeVendors = vendors.filter(v => v.isActive); const suspendedVendors = vendors.filter(v => !v.isActive); const adminVendors = vendors.filter(v => v.isAdmin); const totalVendors = pagination?.total || vendors.length; const stats = [ { title: "Total Vendors", value: totalVendors, description: "Registered vendors", icon: Store, }, { title: "Active Vendors", value: activeVendors.length, description: `${vendors.length > 0 ? Math.round((activeVendors.length / vendors.length) * 100) : 0}% active rate`, icon: UserCheck, }, { title: "Suspended", value: suspendedVendors.length, description: `${vendors.length > 0 ? Math.round((suspendedVendors.length / vendors.length) * 100) : 0}% suspension rate`, icon: UserX, }, { title: "Admin Users", value: adminVendors.length, description: "Administrative access", icon: ShieldAlert, }, ]; return (

All Vendors

Manage vendor accounts and permissions

{/* Stats Cards */}
{stats.map((stat, i) => ( {stat.title}
{stat.value}

{stat.description}

))}
{/* Search and Filters */}
Vendor Management View and manage all vendor accounts
setSearchQuery(e.target.value)} />
Vendor Store Status Join Date Last Login Actions {loading ? (

Loading vendors...

) : filteredVendors.length === 0 ? ( {searchQuery.trim() ? "No vendors found matching your search" : "No vendors found"} ) : ( filteredVendors.map((vendor, index) => (
{vendor.username.substring(0, 2).toUpperCase()}
{vendor.username}
{vendor.storeId ? (
{vendor.storeId}
) : (
No store
)}
{vendor.isActive ? "Active" : "Suspended"} {vendor.isAdmin && ( Admin )}
{vendor.createdAt ? new Date(vendor.createdAt).toLocaleDateString() : 'N/A'}
{vendor.lastLogin ? new Date(vendor.lastLogin).toLocaleDateString() : 'Never'}
)) )}
{pagination && pagination.totalPages > 1 && (
Page {pagination.page} of {pagination.totalPages}
)}
Update Vendor Store Enter the Store ID to assign to vendor {editingVendor?.username}.
setNewStoreId(e.target.value)} placeholder="Enter 24-character Store ID" className="col-span-3 font-mono" />

Ensure the Store ID corresponds to an existing store in the system.

); }