erp-core-frontend-web/src/features/billing-usage/components/PlanSelector.tsx
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

91 lines
2.6 KiB
TypeScript

import React, { useState } from 'react';
import { PlanCard } from './PlanCard';
import type { SubscriptionPlan, BillingCycle } from '../types';
interface PlanSelectorProps {
plans: SubscriptionPlan[];
selectedPlanId?: string;
currentPlanId?: string;
onSelect: (plan: SubscriptionPlan, billingCycle: BillingCycle) => void;
isLoading?: boolean;
}
export const PlanSelector: React.FC<PlanSelectorProps> = ({
plans,
selectedPlanId,
currentPlanId,
onSelect,
isLoading = false,
}) => {
const [billingCycle, setBillingCycle] = useState<BillingCycle>('monthly');
const activePlans = plans.filter((plan) => plan.isActive && plan.isPublic);
if (isLoading) {
return (
<div className="flex items-center justify-center py-12">
<div className="h-8 w-8 animate-spin rounded-full border-4 border-blue-500 border-t-transparent" />
</div>
);
}
if (activePlans.length === 0) {
return (
<div className="rounded-lg bg-gray-50 p-8 text-center">
<p className="text-gray-500">No hay planes disponibles</p>
</div>
);
}
return (
<div>
<div className="mb-8 flex justify-center">
<div className="inline-flex rounded-lg bg-gray-100 p-1">
<button
type="button"
className={`
rounded-md px-4 py-2 text-sm font-medium transition-colors
${billingCycle === 'monthly'
? 'bg-white text-gray-900 shadow'
: 'text-gray-600 hover:text-gray-900'
}
`}
onClick={() => setBillingCycle('monthly')}
>
Mensual
</button>
<button
type="button"
className={`
rounded-md px-4 py-2 text-sm font-medium transition-colors
${billingCycle === 'annual'
? 'bg-white text-gray-900 shadow'
: 'text-gray-600 hover:text-gray-900'
}
`}
onClick={() => setBillingCycle('annual')}
>
Anual
<span className="ml-1 rounded bg-green-100 px-1.5 py-0.5 text-xs text-green-700">
Ahorra
</span>
</button>
</div>
</div>
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
{activePlans.map((plan) => (
<PlanCard
key={plan.id}
plan={plan}
isSelected={plan.id === selectedPlanId}
isCurrent={plan.id === currentPlanId}
billingCycle={billingCycle}
onSelect={(p) => onSelect(p, billingCycle)}
/>
))}
</div>
</div>
);
};