From 2800f0333583b5f0f4ce448a46fa8ec8e1a1babf Mon Sep 17 00:00:00 2001 From: NotII <46204250+NotII@users.noreply.github.com> Date: Thu, 16 Oct 2025 00:29:32 +0100 Subject: [PATCH] Add VendorsCard to admin dashboard Introduces a new VendorsCard component for managing vendor accounts in the admin dashboard. The card displays vendor details, allows password reset token generation, and handles loading and error states. --- app/admin/page.tsx | 3 +- components/admin/VendorsCard.tsx | 97 ++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 components/admin/VendorsCard.tsx diff --git a/app/admin/page.tsx b/app/admin/page.tsx index 6667371..0067a4b 100644 --- a/app/admin/page.tsx +++ b/app/admin/page.tsx @@ -5,6 +5,7 @@ import BanUserCard from "@/components/admin/BanUserCard"; import RecentOrdersCard from "@/components/admin/RecentOrdersCard"; import SystemStatusCard from "@/components/admin/SystemStatusCard"; import InvitationsListCard from "@/components/admin/InvitationsListCard"; +import VendorsCard from "@/components/admin/VendorsCard"; export default function AdminPage() { return ( @@ -16,7 +17,7 @@ export default function AdminPage() {
- + diff --git a/components/admin/VendorsCard.tsx b/components/admin/VendorsCard.tsx new file mode 100644 index 0000000..dba015a --- /dev/null +++ b/components/admin/VendorsCard.tsx @@ -0,0 +1,97 @@ +"use client"; +import { useEffect, useState } from "react"; +import { fetchClient } from "@/lib/api-client"; + +interface Vendor { + _id: string; + username: string; + email?: string; + isAdmin: boolean; + createdAt: string; + lastLogin?: string; +} + +export default function VendorsCard() { + const [vendors, setVendors] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const [resetTokens, setResetTokens] = useState>({}); + + useEffect(() => { + let mounted = true; + (async () => { + try { + const data = await fetchClient("/admin/vendors"); + if (mounted) setVendors(data); + } catch (e: any) { + if (mounted) setError(e?.message || "Failed to load vendors"); + } finally { + if (mounted) setLoading(false); + } + })(); + return () => { mounted = false; }; + }, []); + + async function generateResetToken(vendorId: string) { + try { + const res = await fetchClient<{ token: string; expiresAt: string }>("/admin/password-reset-token", { + method: "POST", + body: { vendorId } + }); + setResetTokens(prev => ({ ...prev, [vendorId]: res.token })); + } catch (e: any) { + setError(e?.message || "Failed to generate reset token"); + } + } + + return ( +
+

Vendors

+

Manage vendor accounts and access

+ + {loading ? ( +

Loading...

+ ) : error ? ( +

{error}

+ ) : vendors.length === 0 ? ( +

No vendors found

+ ) : ( +
+ {vendors.map((vendor) => ( +
+
+
+
{vendor.username}
+
+ {vendor.email && `${vendor.email} · `} + Created: {new Date(vendor.createdAt).toLocaleDateString()} + {vendor.lastLogin && ` · Last login: ${new Date(vendor.lastLogin).toLocaleDateString()}`} +
+
+
+ {vendor.isAdmin && ( + + Admin + + )} + +
+
+ {resetTokens[vendor._id] && ( +
+
{resetTokens[vendor._id]}
+
Copy this token to share with the vendor
+
+ )} +
+ ))} +
+ )} +
+ ); +}