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
+
+ )}
+
+ ))}
+
+ )}
+
+ );
+}