From 3cd2cdafa9ee9d6b78329387644f052fdba6bc05 Mon Sep 17 00:00:00 2001 From: alorig <220087330+alorig@users.noreply.github.com> Date: Fri, 5 Dec 2025 14:17:07 +0500 Subject: [PATCH] 34324 --- frontend/src/App.tsx | 6 + .../src/pages/Admin/AdminCreditCostsPage.tsx | 161 ++++++++++++++++++ frontend/src/services/billing.api.ts | 4 +- 3 files changed, 169 insertions(+), 2 deletions(-) create mode 100644 frontend/src/pages/Admin/AdminCreditCostsPage.tsx diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index dcdaed20..05284a44 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -77,6 +77,7 @@ const AdminAccountLimitsPage = lazy(() => import("./pages/admin/AdminAccountLimi const AdminAllInvoicesPage = lazy(() => import("./pages/admin/AdminAllInvoicesPage")); const AdminAllPaymentsPage = lazy(() => import("./pages/admin/AdminAllPaymentsPage")); const AdminCreditPackagesPage = lazy(() => import("./pages/admin/AdminCreditPackagesPage")); +const AdminCreditCostsPage = lazy(() => import("./pages/admin/AdminCreditCostsPage")); const AdminAllUsersPage = lazy(() => import("./pages/admin/AdminAllUsersPage")); const AdminRolesPermissionsPage = lazy(() => import("./pages/admin/AdminRolesPermissionsPage")); const AdminActivityLogsPage = lazy(() => import("./pages/admin/AdminActivityLogsPage")); @@ -451,6 +452,11 @@ export default function App() { } /> + + + + } /> {/* Admin User Administration */} ([]); + const [loading, setLoading] = useState(true); + const [savingId, setSavingId] = useState(null); + const [error, setError] = useState(''); + + useEffect(() => { + loadCosts(); + }, []); + + const loadCosts = async () => { + try { + setLoading(true); + const data = await getCreditCosts(); + setCosts(data.results || []); + } catch (err: any) { + setError(err.message || 'Failed to load credit costs'); + } finally { + setLoading(false); + } + }; + + const handleSave = async (cost: CreditCostConfig) => { + try { + setSavingId(cost.id); + await updateCreditCosts([ + { operation_type: cost.operation_type, credits_cost: Number(cost.credits_cost) || 0 }, + ]); + await loadCosts(); + } catch (err: any) { + setError(err.message || 'Failed to update credit cost'); + } finally { + setSavingId(null); + } + }; + + const updateLocalCost = (id: number, value: string) => { + setCosts((prev) => + prev.map((c) => (c.id === id ? { ...c, credits_cost: value as any } : c)), + ); + }; + + if (loading) { + return ( +
+ +
+ ); + } + + return ( +
+ + +
+

Credit Costs

+

+ Configure credits required for each billable operation. +

+
+ + {error && ( +
+ +

{error}

+
+ )} + + +
+ + + + + + + + + + + + + {costs.length === 0 ? ( + + + + ) : ( + costs.map((cost) => ( + + + + + + + + + )) + )} + +
+ Operation + + Display Name + + Credits Cost + + Unit + + Description + + Actions +
+ No credit costs configured +
+ {cost.operation_type} + + {cost.display_name || '-'} + + updateLocalCost(cost.id, e.target.value)} + className="w-24 px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 dark:bg-gray-800 dark:text-white" + /> + + {cost.unit} + + {cost.description} + + +
+
+
+
+ ); +} + diff --git a/frontend/src/services/billing.api.ts b/frontend/src/services/billing.api.ts index 4beffcdc..69611c8c 100644 --- a/frontend/src/services/billing.api.ts +++ b/frontend/src/services/billing.api.ts @@ -332,7 +332,7 @@ export async function getCreditCosts(): Promise<{ results: CreditCostConfig[]; count: number; }> { - return fetchAPI('/v1/admin/credit-costs/'); + return fetchAPI('/v1/admin/billing/credit-costs/'); } export async function updateCreditCosts( @@ -344,7 +344,7 @@ export async function updateCreditCosts( message: string; updated_count: number; }> { - return fetchAPI('/v1/admin/credit-costs/', { + return fetchAPI('/v1/admin/billing/credit-costs/', { method: 'POST', body: JSON.stringify({ costs }), });