ui-nyla/src/hooks/useBilling.ts
ValueOn AG 7eb305f910
Some checks failed
Deploy Nyla Frontend to Integration / deploy (push) Failing after 56s
cp adapted to 2026 poweron
2026-06-09 09:53:38 +02:00

349 lines
9.7 KiB
TypeScript

// Copyright (c) 2026 PowerOn AG
// All rights reserved.
/**
* useBilling Hook
*
* Hook für die Verwaltung von Billing-Daten.
* Bietet Zugriff auf Guthaben, Transaktionen, Statistiken und Admin-Funktionen.
*/
import { useState, useEffect, useCallback } from 'react';
import { useApiRequest } from './useApi';
import {
fetchBalances,
fetchBalanceForMandate,
fetchTransactions,
fetchTransactionsPaginated,
fetchStatistics,
fetchAllowedProviders,
fetchSettingsAdmin,
updateSettingsAdmin,
addCreditAdmin,
createCheckoutSession as createCheckoutSessionApi,
fetchAccountsAdmin,
fetchTransactionsAdmin,
fetchUsersForMandateAdmin,
type BillingBalance,
type BillingTransaction,
type BillingSettings,
type BillingSettingsUpdate,
type UsageReport,
type AccountSummary,
type CreditAddRequest,
type CheckoutCreateRequest,
type MandateUserSummary,
type StatisticsRangeRequest,
type BillingBucketSize,
type BillingTransactionsPaginationParams,
} from '../api/billingApi';
import type { GroupLayout } from '../api/connectionApi';
// Re-export types
export type {
BillingBalance,
BillingTransaction,
BillingSettings,
BillingSettingsUpdate,
UsageReport,
AccountSummary,
CreditAddRequest,
MandateUserSummary,
StatisticsRangeRequest,
BillingBucketSize,
};
export type { TransactionType, ReferenceType, BillingTransactionsPaginationParams } from '../api/billingApi';
/**
* Hook for user billing operations
*/
export function useBilling() {
const [balances, setBalances] = useState<BillingBalance[]>([]);
const [transactions, setTransactions] = useState<BillingTransaction[]>([]);
const [transactionsPagination, setTransactionsPagination] = useState<{
currentPage: number;
pageSize: number;
totalItems: number;
totalPages: number;
} | null>(null);
const [transactionsGroupLayout, setTransactionsGroupLayout] = useState<GroupLayout | null>(null);
const [transactionsAppliedView, setTransactionsAppliedView] = useState<{
viewKey?: string;
displayName?: string;
} | null>(null);
const [statistics, setStatistics] = useState<UsageReport | null>(null);
const [allowedProviders, setAllowedProviders] = useState<string[]>([]);
const { request, isLoading: loading, error } = useApiRequest();
// Fetch all balances for the user
const loadBalances = useCallback(async () => {
try {
const data = await fetchBalances(request);
setBalances(Array.isArray(data) ? data : []);
return data;
} catch (err) {
console.error('Error loading balances:', err);
setBalances([]);
return [];
}
}, [request]);
// Fetch balance for a specific mandate
const loadBalanceForMandate = useCallback(async (mandateId: string) => {
try {
return await fetchBalanceForMandate(request, mandateId);
} catch (err) {
console.error('Error loading balance for mandate:', err);
return null;
}
}, [request]);
// Fetch transactions
const loadTransactions = useCallback(async (limit: number = 50, offset: number = 0) => {
try {
const data = await fetchTransactions(request, limit, offset);
setTransactions(Array.isArray(data) ? data : []);
setTransactionsPagination(null);
setTransactionsGroupLayout(null);
setTransactionsAppliedView(null);
return data;
} catch (err) {
console.error('Error loading transactions:', err);
setTransactions([]);
setTransactionsPagination(null);
setTransactionsGroupLayout(null);
setTransactionsAppliedView(null);
return [];
}
}, [request]);
const refetchTransactions = useCallback(async (params?: BillingTransactionsPaginationParams) => {
try {
const data = await fetchTransactionsPaginated(request, params);
setTransactions(Array.isArray(data.items) ? data.items : []);
setTransactionsPagination(data.pagination ?? null);
setTransactionsGroupLayout(data.groupLayout ?? null);
setTransactionsAppliedView(data.appliedView ?? null);
return data;
} catch (err) {
console.error('Error loading transactions:', err);
setTransactions([]);
setTransactionsPagination(null);
setTransactionsGroupLayout(null);
setTransactionsAppliedView(null);
return null;
}
}, [request]);
const loadStatistics = useCallback(async (range: StatisticsRangeRequest) => {
try {
const data = await fetchStatistics(request, range);
setStatistics(data);
return data;
} catch (err) {
console.error('Error loading statistics:', err);
setStatistics(null);
return null;
}
}, [request]);
// Fetch allowed providers
const loadAllowedProviders = useCallback(async () => {
try {
const data = await fetchAllowedProviders(request);
setAllowedProviders(Array.isArray(data) ? data : []);
return data;
} catch (err) {
console.error('Error loading allowed providers:', err);
setAllowedProviders([]);
return [];
}
}, [request]);
// Initial load
useEffect(() => {
loadBalances();
loadAllowedProviders();
}, []);
return {
balances,
transactions,
transactionsPagination,
transactionsGroupLayout,
transactionsAppliedView,
statistics,
allowedProviders,
loading,
error,
loadBalances,
loadBalanceForMandate,
loadTransactions,
refetchTransactions,
loadStatistics,
loadAllowedProviders,
refetch: loadBalances,
};
}
/**
* Hook for admin billing operations
*/
export function useBillingAdmin(mandateId?: string) {
const [settings, setSettings] = useState<BillingSettings | null>(null);
const [accounts, setAccounts] = useState<AccountSummary[]>([]);
const [transactions, setTransactions] = useState<BillingTransaction[]>([]);
const [users, setUsers] = useState<MandateUserSummary[]>([]);
const { request, isLoading: loading, error } = useApiRequest();
// Fetch settings for a mandate
const loadSettings = useCallback(async (targetMandateId?: string) => {
const mId = targetMandateId || mandateId;
if (!mId) return null;
try {
const data = await fetchSettingsAdmin(request, mId);
setSettings(data);
return data;
} catch (err) {
console.error('Error loading billing settings:', err);
setSettings(null);
return null;
}
}, [request, mandateId]);
// Fetch accounts for a mandate
const loadAccounts = useCallback(async (targetMandateId?: string) => {
const mId = targetMandateId || mandateId;
if (!mId) return [];
try {
const data = await fetchAccountsAdmin(request, mId);
setAccounts(Array.isArray(data) ? data : []);
return data;
} catch (err) {
console.error('Error loading accounts:', err);
setAccounts([]);
return [];
}
}, [request, mandateId]);
// Fetch transactions for a mandate
const loadTransactions = useCallback(async (targetMandateId?: string, limit: number = 100) => {
const mId = targetMandateId || mandateId;
if (!mId) return [];
try {
const data = await fetchTransactionsAdmin(request, mId, limit);
setTransactions(Array.isArray(data) ? data : []);
return data;
} catch (err) {
console.error('Error loading transactions:', err);
setTransactions([]);
return [];
}
}, [request, mandateId]);
// Fetch users for a mandate
const loadUsers = useCallback(async (targetMandateId?: string) => {
const mId = targetMandateId || mandateId;
if (!mId) return [];
try {
const data = await fetchUsersForMandateAdmin(request, mId);
setUsers(Array.isArray(data) ? data : []);
return data;
} catch (err) {
console.error('Error loading users:', err);
setUsers([]);
return [];
}
}, [request, mandateId]);
const saveSettings = useCallback(
async (settingsUpdate: BillingSettingsUpdate, targetMandateId?: string) => {
const mId = targetMandateId || mandateId;
if (!mId) return null;
try {
const data = await updateSettingsAdmin(request, mId, settingsUpdate);
setSettings(data);
return data;
} catch (err) {
console.error('Error saving billing settings:', err);
throw err;
}
},
[request, mandateId]
);
// Add credit (manual, admin)
const addCredit = useCallback(
async (creditRequest: CreditAddRequest, targetMandateId?: string) => {
const mId = targetMandateId || mandateId;
if (!mId) return null;
try {
const result = await addCreditAdmin(request, mId, creditRequest);
await loadAccounts(mId);
return result;
} catch (err) {
console.error('Error adding credit:', err);
throw err;
}
},
[request, mandateId, loadAccounts]
);
// Create Stripe Checkout Session (returns redirect URL)
const createCheckout = useCallback(
async (checkoutRequest: CheckoutCreateRequest, targetMandateId?: string) => {
const mId = targetMandateId || mandateId;
if (!mId) return null;
try {
return await createCheckoutSessionApi(request, mId, checkoutRequest);
} catch (err) {
console.error('Error creating checkout session:', err);
throw err;
}
},
[request, mandateId]
);
// Load data when mandateId changes
useEffect(() => {
if (mandateId) {
loadSettings();
loadAccounts();
loadTransactions();
loadUsers();
}
}, [mandateId]);
return {
settings,
accounts,
transactions,
users,
loading,
error,
loadSettings,
saveSettings,
addCredit,
createCheckout,
loadAccounts,
loadTransactions,
loadUsers,
refetch: () => {
if (mandateId) {
loadSettings();
loadAccounts();
loadTransactions();
loadUsers();
}
},
};
}
export default useBilling;