erp-core-frontend-v2/src/features/billing-usage/hooks/usePlans.ts
rckrdmrd 28b27565f8 feat(billing): Add billing-usage frontend module with components, pages and routes
- Add billing-usage feature module with types, API clients, hooks, and components
- Create PlanCard, PlanSelector, SubscriptionStatusBadge, InvoiceList, UsageSummaryCard, CouponInput components
- Add BillingPage, PlansPage, InvoicesPage, UsagePage
- Update routes to include billing section

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 08:23:59 -06:00

156 lines
4.0 KiB
TypeScript

import { useState, useCallback, useEffect } from 'react';
import { plansApi } from '../api';
import type { SubscriptionPlan, PlanFilters, CreatePlanDto, UpdatePlanDto } from '../types';
interface UsePlansState {
plans: SubscriptionPlan[];
total: number;
page: number;
totalPages: number;
isLoading: boolean;
error: string | null;
}
interface UsePlansReturn extends UsePlansState {
filters: PlanFilters;
setFilters: (filters: PlanFilters) => void;
refresh: () => Promise<void>;
createPlan: (data: CreatePlanDto) => Promise<SubscriptionPlan>;
updatePlan: (id: string, data: UpdatePlanDto) => Promise<SubscriptionPlan>;
deletePlan: (id: string) => Promise<void>;
activatePlan: (id: string) => Promise<void>;
deactivatePlan: (id: string) => Promise<void>;
}
export function usePlans(initialFilters?: PlanFilters): UsePlansReturn {
const [state, setState] = useState<UsePlansState>({
plans: [],
total: 0,
page: 1,
totalPages: 1,
isLoading: true,
error: null,
});
const [filters, setFilters] = useState<PlanFilters>(initialFilters || { page: 1, limit: 10 });
const fetchPlans = useCallback(async () => {
setState((prev) => ({ ...prev, isLoading: true, error: null }));
try {
const response = await plansApi.getAll(filters);
setState({
plans: response.data,
total: response.meta.total,
page: response.meta.page,
totalPages: response.meta.totalPages,
isLoading: false,
error: null,
});
} catch (err) {
setState((prev) => ({
...prev,
isLoading: false,
error: err instanceof Error ? err.message : 'Error al cargar planes',
}));
}
}, [filters]);
useEffect(() => {
fetchPlans();
}, [fetchPlans]);
const createPlan = async (data: CreatePlanDto): Promise<SubscriptionPlan> => {
const plan = await plansApi.create(data);
await fetchPlans();
return plan;
};
const updatePlan = async (id: string, data: UpdatePlanDto): Promise<SubscriptionPlan> => {
const plan = await plansApi.update(id, data);
await fetchPlans();
return plan;
};
const deletePlan = async (id: string): Promise<void> => {
await plansApi.delete(id);
await fetchPlans();
};
const activatePlan = async (id: string): Promise<void> => {
await plansApi.activate(id);
await fetchPlans();
};
const deactivatePlan = async (id: string): Promise<void> => {
await plansApi.deactivate(id);
await fetchPlans();
};
return {
...state,
filters,
setFilters,
refresh: fetchPlans,
createPlan,
updatePlan,
deletePlan,
activatePlan,
deactivatePlan,
};
}
export function usePlan(id: string | undefined) {
const [plan, setPlan] = useState<SubscriptionPlan | null>(null);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const fetchPlan = useCallback(async () => {
if (!id) {
setIsLoading(false);
return;
}
setIsLoading(true);
setError(null);
try {
const data = await plansApi.getById(id);
setPlan(data);
} catch (err) {
setError(err instanceof Error ? err.message : 'Error al cargar plan');
} finally {
setIsLoading(false);
}
}, [id]);
useEffect(() => {
fetchPlan();
}, [fetchPlan]);
return { plan, isLoading, error, refresh: fetchPlan };
}
export function usePublicPlans() {
const [plans, setPlans] = useState<SubscriptionPlan[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const fetchPlans = useCallback(async () => {
setIsLoading(true);
setError(null);
try {
const data = await plansApi.getPublic();
setPlans(data);
} catch (err) {
setError(err instanceof Error ? err.message : 'Error al cargar planes');
} finally {
setIsLoading(false);
}
}, []);
useEffect(() => {
fetchPlans();
}, [fetchPlans]);
return { plans, isLoading, error, refresh: fetchPlans };
}