From b18f8907a33302f09579646cadcf9ddef673965e Mon Sep 17 00:00:00 2001 From: robin Date: Thu, 18 Dec 2025 15:29:13 +0100 Subject: [PATCH] feat: add plan assignment to user management - Added plan dropdown to user edit modal - Shows current plan with highlighted card - Allows admin to assign/change user's subscription plan - Loads user's current plan when opening edit modal - Updates plan via setUserPlan service - Visual feedback with success/error messages Admins can now: - View user's current subscription plan - Assign users to different plans (Starter, Bronze, Silver, Gold) - See plan details (credits/month, price) in dropdown This completes the subscription plan system! --- src/app/admin/users/page.tsx | 6 +- src/components/UserManagementClient.tsx | 82 +++++++++++++++++++++++-- 2 files changed, 83 insertions(+), 5 deletions(-) diff --git a/src/app/admin/users/page.tsx b/src/app/admin/users/page.tsx index 19ebcb2..be1b5d5 100644 --- a/src/app/admin/users/page.tsx +++ b/src/app/admin/users/page.tsx @@ -3,6 +3,7 @@ import { cookies } from 'next/headers'; import { redirect } from 'next/navigation'; import { checkIsAdmin } from '@/services/track-api-usage'; import { getAllUsersWithCredits } from '@/services/admin-credit-service'; +import { getAllPlans } from '@/services/subscription-service'; import Link from 'next/link'; import { ChevronLeft, Users, Coins, TrendingUp, TrendingDown } from 'lucide-react'; import UserManagementClient from '@/components/UserManagementClient'; @@ -23,6 +24,9 @@ export default async function AdminUsersPage() { // Fetch all users with credits const users = await getAllUsersWithCredits(); + // Fetch all plans + const plans = await getAllPlans(); + // Calculate statistics const totalUsers = users.length; const totalCreditsInCirculation = users.reduce((sum, u) => sum + u.balance, 0); @@ -91,7 +95,7 @@ export default async function AdminUsersPage() { {/* User Management Table */} - + ); diff --git a/src/components/UserManagementClient.tsx b/src/components/UserManagementClient.tsx index 94edb60..350eb57 100644 --- a/src/components/UserManagementClient.tsx +++ b/src/components/UserManagementClient.tsx @@ -1,8 +1,9 @@ 'use client'; -import { useState } from 'react'; +import { useState, useEffect } from 'react'; import { Edit, Plus, Search, X, Check, AlertCircle } from 'lucide-react'; import { updateUserCredits, setUserDailyLimit, setUserApiCosts } from '@/services/admin-credit-service'; +import { setUserPlan, getUserSubscription, type SubscriptionPlan } from '@/services/subscription-service'; interface User { id: string; @@ -19,9 +20,10 @@ interface User { interface UserManagementClientProps { initialUsers: User[]; + plans: SubscriptionPlan[]; } -export default function UserManagementClient({ initialUsers }: UserManagementClientProps) { +export default function UserManagementClient({ initialUsers, plans }: UserManagementClientProps) { const [users, setUsers] = useState(initialUsers); const [searchTerm, setSearchTerm] = useState(''); const [editingUser, setEditingUser] = useState(null); @@ -30,6 +32,8 @@ export default function UserManagementClient({ initialUsers }: UserManagementCli const [dailyLimit, setDailyLimit] = useState(''); const [googleCost, setGoogleCost] = useState(''); const [geminiCost, setGeminiCost] = useState(''); + const [selectedPlan, setSelectedPlan] = useState(''); + const [currentPlan, setCurrentPlan] = useState(null); const [loading, setLoading] = useState(false); const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null); @@ -38,6 +42,16 @@ export default function UserManagementClient({ initialUsers }: UserManagementCli user.username.toLowerCase().includes(searchTerm.toLowerCase()) ); + // Load user's current plan when editing + useEffect(() => { + if (editingUser) { + getUserSubscription(editingUser.id).then(({ plan }) => { + setCurrentPlan(plan); + setSelectedPlan(plan?.id || ''); + }); + } + }, [editingUser]); + const handleEditUser = (user: User) => { setEditingUser(user); setCreditAmount(''); @@ -48,6 +62,29 @@ export default function UserManagementClient({ initialUsers }: UserManagementCli setMessage(null); }; + const handleUpdatePlan = async () => { + if (!editingUser || !selectedPlan) { + setMessage({ type: 'error', text: 'Please select a plan' }); + return; + } + + setLoading(true); + setMessage(null); + + const result = await setUserPlan(editingUser.id, selectedPlan); + + if (result.success) { + setMessage({ type: 'success', text: 'Plan updated successfully' }); + // Reload current plan + const { plan } = await getUserSubscription(editingUser.id); + setCurrentPlan(plan); + } else { + setMessage({ type: 'error', text: result.error || 'Failed to update plan' }); + } + + setLoading(false); + }; + const handleUpdateCredits = async () => { if (!editingUser || !creditAmount || !reason) { setMessage({ type: 'error', text: 'Please fill in all fields' }); @@ -215,8 +252,8 @@ export default function UserManagementClient({ initialUsers }: UserManagementCli {message && (
{message.type === 'success' ? : } {message.text} @@ -267,6 +304,43 @@ export default function UserManagementClient({ initialUsers }: UserManagementCli
+ {/* Subscription Plan */} +
+

Subscription Plan

+ {currentPlan && ( +
+
Current Plan
+
{currentPlan.display_name}
+
{currentPlan.monthly_credits} credits/month
+
+ )} +
+ + +
+ +
+ +
+ {/* Settings */}

User Settings