From c7c2167908f3a85f6b3e94cda5dbfcaa4d2f95ee Mon Sep 17 00:00:00 2001 From: c0mrade Date: Tue, 24 Mar 2026 16:55:09 +0300 Subject: [PATCH] fix: admin per-subscription panel data + hide purchased tariffs in create - getPanelInfo/getNodeUsage/getUserDevices: pass subscriptionId - deleteUserDevice/resetUserDevices: pass subscriptionId - Reload panel data when switching between subscriptions - Create subscription: filter out already purchased tariffs --- src/api/adminUsers.ts | 27 +++++++++++++++++------- src/pages/AdminUserDetail.tsx | 39 +++++++++++++++++++++++------------ 2 files changed, 46 insertions(+), 20 deletions(-) diff --git a/src/api/adminUsers.ts b/src/api/adminUsers.ts index 41b9980..67ab7d7 100644 --- a/src/api/adminUsers.ts +++ b/src/api/adminUsers.ts @@ -603,26 +603,33 @@ export const adminUsersApi = { }, // Get panel info - getPanelInfo: async (userId: number): Promise => { - const response = await apiClient.get(`/cabinet/admin/users/${userId}/panel-info`); + getPanelInfo: async (userId: number, subscriptionId?: number): Promise => { + const response = await apiClient.get(`/cabinet/admin/users/${userId}/panel-info`, { + params: subscriptionId != null ? { subscription_id: subscriptionId } : undefined, + }); return response.data; }, // Get node usage (always 30 days with daily breakdown) - getNodeUsage: async (userId: number): Promise => { - const response = await apiClient.get(`/cabinet/admin/users/${userId}/node-usage`); + getNodeUsage: async (userId: number, subscriptionId?: number): Promise => { + const response = await apiClient.get(`/cabinet/admin/users/${userId}/node-usage`, { + params: subscriptionId != null ? { subscription_id: subscriptionId } : undefined, + }); return response.data; }, // Get user devices getUserDevices: async ( userId: number, + subscriptionId?: number, ): Promise<{ devices: { hwid: string; platform: string; device_model: string; created_at: string | null }[]; total: number; device_limit: number; }> => { - const response = await apiClient.get(`/cabinet/admin/users/${userId}/devices`); + const response = await apiClient.get(`/cabinet/admin/users/${userId}/devices`, { + params: subscriptionId != null ? { subscription_id: subscriptionId } : undefined, + }); return response.data; }, @@ -630,16 +637,22 @@ export const adminUsersApi = { deleteUserDevice: async ( userId: number, hwid: string, + subscriptionId?: number, ): Promise<{ success: boolean; message: string; deleted_hwid: string | null }> => { - const response = await apiClient.delete(`/cabinet/admin/users/${userId}/devices/${hwid}`); + const response = await apiClient.delete(`/cabinet/admin/users/${userId}/devices/${hwid}`, { + params: subscriptionId != null ? { subscription_id: subscriptionId } : undefined, + }); return response.data; }, // Reset all devices resetUserDevices: async ( userId: number, + subscriptionId?: number, ): Promise<{ success: boolean; message: string; deleted_count: number }> => { - const response = await apiClient.delete(`/cabinet/admin/users/${userId}/devices`); + const response = await apiClient.delete(`/cabinet/admin/users/${userId}/devices`, { + params: subscriptionId != null ? { subscription_id: subscriptionId } : undefined, + }); return response.data; }, diff --git a/src/pages/AdminUserDetail.tsx b/src/pages/AdminUserDetail.tsx index 188ec57..b402ae8 100644 --- a/src/pages/AdminUserDetail.tsx +++ b/src/pages/AdminUserDetail.tsx @@ -443,27 +443,27 @@ export default function AdminUserDetail() { if (!userId) return; try { setPanelInfoLoading(true); - const data = await adminUsersApi.getPanelInfo(userId); + const data = await adminUsersApi.getPanelInfo(userId, activeSubscriptionId ?? undefined); setPanelInfo(data); } catch { } finally { setPanelInfoLoading(false); } - }, [userId]); + }, [userId, activeSubscriptionId]); const loadNodeUsage = useCallback(async () => { if (!userId) return; try { - const data = await adminUsersApi.getNodeUsage(userId); + const data = await adminUsersApi.getNodeUsage(userId, activeSubscriptionId ?? undefined); setNodeUsage(data); } catch {} - }, [userId]); + }, [userId, activeSubscriptionId]); const loadDevices = useCallback(async () => { if (!userId) return; try { setDevicesLoading(true); - const data = await adminUsersApi.getUserDevices(userId); + const data = await adminUsersApi.getUserDevices(userId, activeSubscriptionId ?? undefined); setDevices(data.devices); setDevicesTotal(data.total); setDeviceLimit(data.device_limit); @@ -471,7 +471,7 @@ export default function AdminUserDetail() { } finally { setDevicesLoading(false); } - }, [userId]); + }, [userId, activeSubscriptionId]); const loadSubscriptionData = useCallback(async () => { await Promise.all([loadPanelInfo(), loadNodeUsage(), loadDevices()]); @@ -697,7 +697,7 @@ export default function AdminUserDetail() { if (!userId) return; setActionLoading(true); try { - await adminUsersApi.deleteUserDevice(userId, hwid); + await adminUsersApi.deleteUserDevice(userId, hwid, activeSubscriptionId ?? undefined); notify.success(t('admin.users.detail.devices.deleted')); await loadDevices(); } catch { @@ -711,7 +711,7 @@ export default function AdminUserDetail() { if (!userId) return; setActionLoading(true); try { - await adminUsersApi.resetUserDevices(userId); + await adminUsersApi.resetUserDevices(userId, activeSubscriptionId ?? undefined); notify.success(t('admin.users.detail.devices.allDeleted')); await loadDevices(); } catch { @@ -1681,11 +1681,24 @@ export default function AdminUserDetail() { className="input" > - {tariffs.map((tariffItem) => ( - - ))} + {tariffs + .filter((tariffItem) => { + // In multi-tariff: hide tariffs user already has + if (userSubscriptions.length > 0) { + const purchasedIds = new Set( + userSubscriptions + .filter((s) => s.is_active || s.status === 'trial') + .map((s) => s.tariff_id), + ); + return !purchasedIds.has(tariffItem.id); + } + return true; + }) + .map((tariffItem) => ( + + ))}