123
This commit is contained in:
@@ -3,6 +3,7 @@ import { useToast } from '../../components/ui/toast/ToastContainer';
|
||||
import { getCreditTransactions, getCreditBalance, CreditTransaction as BillingTransaction, CreditBalance } from '../../services/billing.api';
|
||||
import { Card } from '../../components/ui/card';
|
||||
import Badge from '../../components/ui/badge/Badge';
|
||||
import { CompactPagination } from '../ui/pagination';
|
||||
|
||||
// Credit costs per operation (copied from Billing usage page)
|
||||
const CREDIT_COSTS: Record<string, { cost: number | string; description: string }> = {
|
||||
@@ -22,6 +23,8 @@ export default function BillingUsagePanel() {
|
||||
const [transactions, setTransactions] = useState<BillingTransaction[]>([]);
|
||||
const [balance, setBalance] = useState<CreditBalance | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [page, setPage] = useState(1);
|
||||
const [pageSize, setPageSize] = useState(10);
|
||||
|
||||
useEffect(() => {
|
||||
loadUsage();
|
||||
@@ -43,6 +46,9 @@ export default function BillingUsagePanel() {
|
||||
}
|
||||
};
|
||||
|
||||
const totalPages = Math.max(1, Math.ceil(transactions.length / pageSize));
|
||||
const paginated = transactions.slice((page - 1) * pageSize, page * pageSize);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="p-4">
|
||||
@@ -123,7 +129,7 @@ export default function BillingUsagePanel() {
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{transactions.map((txn) => (
|
||||
{paginated.map((txn) => (
|
||||
<tr key={txn.id} className="border-b border-gray-100 dark:border-gray-800">
|
||||
<td className="py-3 px-4 text-sm text-gray-900 dark:text-white">{new Date(txn.created_at).toLocaleString()}</td>
|
||||
<td className="py-3 px-4">
|
||||
@@ -144,6 +150,23 @@ export default function BillingUsagePanel() {
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{transactions.length > 0 && (
|
||||
<div className="mt-4 flex justify-between items-center">
|
||||
<div className="text-sm text-gray-500 dark:text-gray-400">
|
||||
Showing {(page - 1) * pageSize + 1}-{Math.min(page * pageSize, transactions.length)} of {transactions.length}
|
||||
</div>
|
||||
<CompactPagination
|
||||
currentPage={page}
|
||||
totalPages={totalPages}
|
||||
pageSize={pageSize}
|
||||
onPageChange={(p) => setPage(p)}
|
||||
onPageSizeChange={(size) => {
|
||||
setPageSize(size);
|
||||
setPage(1);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -134,9 +134,11 @@ export default function TeamManagementPage() {
|
||||
<div className="flex justify-end">
|
||||
<Button
|
||||
variant="primary"
|
||||
tone="brand"
|
||||
size="md"
|
||||
startIcon={<UserPlus className="w-4 h-4" />}
|
||||
onClick={() => setShowInviteModal(true)}
|
||||
>
|
||||
<UserPlus className="w-4 h-4 mr-2" />
|
||||
Invite Team Member
|
||||
</Button>
|
||||
</div>
|
||||
@@ -215,9 +217,11 @@ export default function TeamManagementPage() {
|
||||
<div className="flex justify-end">
|
||||
<Button
|
||||
variant="primary"
|
||||
tone="brand"
|
||||
size="md"
|
||||
startIcon={<UserPlus className="w-4 h-4" />}
|
||||
onClick={() => setShowInviteModal(true)}
|
||||
>
|
||||
<UserPlus className="w-4 h-4 mr-2" />
|
||||
Send Invitation
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -12,6 +12,7 @@ import { Card } from '../../components/ui/card';
|
||||
import Badge from '../../components/ui/badge/Badge';
|
||||
import BillingUsagePanel from '../../components/billing/BillingUsagePanel';
|
||||
import BillingBalancePanel from '../../components/billing/BillingBalancePanel';
|
||||
import Button from '../../components/ui/button/Button';
|
||||
|
||||
type TabType = 'credits' | 'api' | 'costs';
|
||||
|
||||
@@ -92,36 +93,20 @@ export default function UsageAnalyticsPage() {
|
||||
|
||||
{/* Period Selector */}
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={() => setPeriod(7)}
|
||||
className={`px-4 py-2 rounded-md text-sm font-medium ${
|
||||
period === 7
|
||||
? 'bg-primary-600 text-white'
|
||||
: 'bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300'
|
||||
}`}
|
||||
{[7, 30, 90].map((value) => {
|
||||
const isActive = period === value;
|
||||
return (
|
||||
<Button
|
||||
key={value}
|
||||
size="sm"
|
||||
variant={isActive ? 'primary' : 'secondary'}
|
||||
tone={isActive ? 'brand' : 'neutral'}
|
||||
onClick={() => setPeriod(value)}
|
||||
>
|
||||
7 Days
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setPeriod(30)}
|
||||
className={`px-4 py-2 rounded-md text-sm font-medium ${
|
||||
period === 30
|
||||
? 'bg-primary-600 text-white'
|
||||
: 'bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300'
|
||||
}`}
|
||||
>
|
||||
30 Days
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setPeriod(90)}
|
||||
className={`px-4 py-2 rounded-md text-sm font-medium ${
|
||||
period === 90
|
||||
? 'bg-primary-600 text-white'
|
||||
: 'bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300'
|
||||
}`}
|
||||
>
|
||||
90 Days
|
||||
</button>
|
||||
{value} Days
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user