mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 17:43:47 +00:00
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
This commit is contained in:
@@ -603,26 +603,33 @@ export const adminUsersApi = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Get panel info
|
// Get panel info
|
||||||
getPanelInfo: async (userId: number): Promise<UserPanelInfo> => {
|
getPanelInfo: async (userId: number, subscriptionId?: number): Promise<UserPanelInfo> => {
|
||||||
const response = await apiClient.get(`/cabinet/admin/users/${userId}/panel-info`);
|
const response = await apiClient.get(`/cabinet/admin/users/${userId}/panel-info`, {
|
||||||
|
params: subscriptionId != null ? { subscription_id: subscriptionId } : undefined,
|
||||||
|
});
|
||||||
return response.data;
|
return response.data;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Get node usage (always 30 days with daily breakdown)
|
// Get node usage (always 30 days with daily breakdown)
|
||||||
getNodeUsage: async (userId: number): Promise<UserNodeUsageResponse> => {
|
getNodeUsage: async (userId: number, subscriptionId?: number): Promise<UserNodeUsageResponse> => {
|
||||||
const response = await apiClient.get(`/cabinet/admin/users/${userId}/node-usage`);
|
const response = await apiClient.get(`/cabinet/admin/users/${userId}/node-usage`, {
|
||||||
|
params: subscriptionId != null ? { subscription_id: subscriptionId } : undefined,
|
||||||
|
});
|
||||||
return response.data;
|
return response.data;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Get user devices
|
// Get user devices
|
||||||
getUserDevices: async (
|
getUserDevices: async (
|
||||||
userId: number,
|
userId: number,
|
||||||
|
subscriptionId?: number,
|
||||||
): Promise<{
|
): Promise<{
|
||||||
devices: { hwid: string; platform: string; device_model: string; created_at: string | null }[];
|
devices: { hwid: string; platform: string; device_model: string; created_at: string | null }[];
|
||||||
total: number;
|
total: number;
|
||||||
device_limit: 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;
|
return response.data;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -630,16 +637,22 @@ export const adminUsersApi = {
|
|||||||
deleteUserDevice: async (
|
deleteUserDevice: async (
|
||||||
userId: number,
|
userId: number,
|
||||||
hwid: string,
|
hwid: string,
|
||||||
|
subscriptionId?: number,
|
||||||
): Promise<{ success: boolean; message: string; deleted_hwid: string | null }> => {
|
): 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;
|
return response.data;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Reset all devices
|
// Reset all devices
|
||||||
resetUserDevices: async (
|
resetUserDevices: async (
|
||||||
userId: number,
|
userId: number,
|
||||||
|
subscriptionId?: number,
|
||||||
): Promise<{ success: boolean; message: string; deleted_count: 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;
|
return response.data;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -443,27 +443,27 @@ export default function AdminUserDetail() {
|
|||||||
if (!userId) return;
|
if (!userId) return;
|
||||||
try {
|
try {
|
||||||
setPanelInfoLoading(true);
|
setPanelInfoLoading(true);
|
||||||
const data = await adminUsersApi.getPanelInfo(userId);
|
const data = await adminUsersApi.getPanelInfo(userId, activeSubscriptionId ?? undefined);
|
||||||
setPanelInfo(data);
|
setPanelInfo(data);
|
||||||
} catch {
|
} catch {
|
||||||
} finally {
|
} finally {
|
||||||
setPanelInfoLoading(false);
|
setPanelInfoLoading(false);
|
||||||
}
|
}
|
||||||
}, [userId]);
|
}, [userId, activeSubscriptionId]);
|
||||||
|
|
||||||
const loadNodeUsage = useCallback(async () => {
|
const loadNodeUsage = useCallback(async () => {
|
||||||
if (!userId) return;
|
if (!userId) return;
|
||||||
try {
|
try {
|
||||||
const data = await adminUsersApi.getNodeUsage(userId);
|
const data = await adminUsersApi.getNodeUsage(userId, activeSubscriptionId ?? undefined);
|
||||||
setNodeUsage(data);
|
setNodeUsage(data);
|
||||||
} catch {}
|
} catch {}
|
||||||
}, [userId]);
|
}, [userId, activeSubscriptionId]);
|
||||||
|
|
||||||
const loadDevices = useCallback(async () => {
|
const loadDevices = useCallback(async () => {
|
||||||
if (!userId) return;
|
if (!userId) return;
|
||||||
try {
|
try {
|
||||||
setDevicesLoading(true);
|
setDevicesLoading(true);
|
||||||
const data = await adminUsersApi.getUserDevices(userId);
|
const data = await adminUsersApi.getUserDevices(userId, activeSubscriptionId ?? undefined);
|
||||||
setDevices(data.devices);
|
setDevices(data.devices);
|
||||||
setDevicesTotal(data.total);
|
setDevicesTotal(data.total);
|
||||||
setDeviceLimit(data.device_limit);
|
setDeviceLimit(data.device_limit);
|
||||||
@@ -471,7 +471,7 @@ export default function AdminUserDetail() {
|
|||||||
} finally {
|
} finally {
|
||||||
setDevicesLoading(false);
|
setDevicesLoading(false);
|
||||||
}
|
}
|
||||||
}, [userId]);
|
}, [userId, activeSubscriptionId]);
|
||||||
|
|
||||||
const loadSubscriptionData = useCallback(async () => {
|
const loadSubscriptionData = useCallback(async () => {
|
||||||
await Promise.all([loadPanelInfo(), loadNodeUsage(), loadDevices()]);
|
await Promise.all([loadPanelInfo(), loadNodeUsage(), loadDevices()]);
|
||||||
@@ -697,7 +697,7 @@ export default function AdminUserDetail() {
|
|||||||
if (!userId) return;
|
if (!userId) return;
|
||||||
setActionLoading(true);
|
setActionLoading(true);
|
||||||
try {
|
try {
|
||||||
await adminUsersApi.deleteUserDevice(userId, hwid);
|
await adminUsersApi.deleteUserDevice(userId, hwid, activeSubscriptionId ?? undefined);
|
||||||
notify.success(t('admin.users.detail.devices.deleted'));
|
notify.success(t('admin.users.detail.devices.deleted'));
|
||||||
await loadDevices();
|
await loadDevices();
|
||||||
} catch {
|
} catch {
|
||||||
@@ -711,7 +711,7 @@ export default function AdminUserDetail() {
|
|||||||
if (!userId) return;
|
if (!userId) return;
|
||||||
setActionLoading(true);
|
setActionLoading(true);
|
||||||
try {
|
try {
|
||||||
await adminUsersApi.resetUserDevices(userId);
|
await adminUsersApi.resetUserDevices(userId, activeSubscriptionId ?? undefined);
|
||||||
notify.success(t('admin.users.detail.devices.allDeleted'));
|
notify.success(t('admin.users.detail.devices.allDeleted'));
|
||||||
await loadDevices();
|
await loadDevices();
|
||||||
} catch {
|
} catch {
|
||||||
@@ -1681,11 +1681,24 @@ export default function AdminUserDetail() {
|
|||||||
className="input"
|
className="input"
|
||||||
>
|
>
|
||||||
<option value="">{t('admin.users.detail.subscription.selectTariff')}</option>
|
<option value="">{t('admin.users.detail.subscription.selectTariff')}</option>
|
||||||
{tariffs.map((tariffItem) => (
|
{tariffs
|
||||||
<option key={tariffItem.id} value={tariffItem.id}>
|
.filter((tariffItem) => {
|
||||||
{tariffItem.name}
|
// In multi-tariff: hide tariffs user already has
|
||||||
</option>
|
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) => (
|
||||||
|
<option key={tariffItem.id} value={tariffItem.id}>
|
||||||
|
{tariffItem.name}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
</select>
|
</select>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
|
|||||||
Reference in New Issue
Block a user