Spaces:
Runtime error
Runtime error
feat: Implement admin management for product requests and affiliate proposals, including new database migrations and expanded dashboard statistics.
7bb5991 | "use server"; | |
| import { db } from "@/lib/db"; | |
| import { | |
| users, | |
| youtubeVideos, | |
| detectedObjects, | |
| interestPledges, | |
| productRequests, | |
| affiliateProposals, | |
| } from "@/lib/db/schema"; | |
| import { count, eq, sql } from "drizzle-orm"; | |
| import { auth } from "@/lib/auth"; | |
| import { headers } from "next/headers"; | |
| import { redirect } from "next/navigation"; | |
| /** | |
| * Ensures the user is an authorized admin. | |
| * Uses ADMIN_EMAILS from environment variables. | |
| */ | |
| async function ensureAdmin() { | |
| const session = await auth.api.getSession({ | |
| headers: await headers() | |
| }); | |
| const adminEmails = process.env.ADMIN_EMAILS?.split(",") || []; | |
| if (!session?.user?.email || !adminEmails.includes(session.user.email)) { | |
| throw new Error("Unauthorized"); | |
| } | |
| } | |
| export async function getAdminStats() { | |
| await ensureAdmin(); | |
| const [userCount] = await db.select({ count: count() }).from(users); | |
| const [pendingAnalysis] = await db.select({ count: count() }).from(youtubeVideos).where(eq(youtubeVideos.scanStatus, 'pending_analysis')); | |
| const [awaitingApproval] = await db.select({ count: count() }).from(youtubeVideos).where(eq(youtubeVideos.scanStatus, 'awaiting_approval')); | |
| const [totalProducts] = await db.select({ count: count() }).from(detectedObjects); | |
| // Interest Items: Detections with 1+ "I want this" requests | |
| const interestCount = await db | |
| .select({ count: sql<number>`count(distinct ${detectedObjects.id})` }) | |
| .from(detectedObjects) | |
| .innerJoin(interestPledges, eq(detectedObjects.id, interestPledges.detectedObjectId)) | |
| .groupBy(detectedObjects.id) | |
| .having(sql`count(${interestPledges.id}) >= 1`); | |
| // Pending Community Requests | |
| const [pendingRequests] = await db.select({ count: count() }) | |
| .from(productRequests) | |
| .where(eq(productRequests.status, 'PENDING')); | |
| // Pending Affiliate Proposals | |
| const [pendingProposals] = await db.select({ count: count() }) | |
| .from(affiliateProposals) | |
| .where(eq(affiliateProposals.status, 'PENDING')); | |
| return { | |
| totalUsers: Number(userCount.count), | |
| pendingAnalysis: Number(pendingAnalysis.count), | |
| awaitingApproval: Number(awaitingApproval.count), | |
| totalProducts: Number(totalProducts.count), | |
| highInterestItems: interestCount.length, | |
| pendingRequests: Number(pendingRequests.count), | |
| pendingProposals: Number(pendingProposals.count), | |
| }; | |
| } | |