Add subcription feature 5

This commit is contained in:
Urtzi Alfaro
2026-01-16 09:55:54 +01:00
parent 483a9f64cd
commit 6b43116efd
51 changed files with 1428 additions and 312 deletions

View File

@@ -33,13 +33,15 @@ const SubscriptionStatusBanner: React.FC<{
isTrial?: boolean;
trialEndsAt?: string;
trialDaysRemaining?: number;
}> = ({ planName, status, nextBilling, cost, onUpgrade, onManagePayment, showUpgradeButton, isTrial, trialEndsAt, trialDaysRemaining }) => {
isPilot?: boolean;
}> = ({ planName, status, nextBilling, cost, onUpgrade, onManagePayment, showUpgradeButton, isTrial, trialEndsAt, trialDaysRemaining, isPilot }) => {
// Determine if we should show trial information
const showTrialInfo = isTrial && trialEndsAt;
const showPilotInfo = isPilot;
return (
<Card className={`p-6 mb-6 ${showTrialInfo
<Card className={`p-6 mb-6 ${showTrialInfo || showPilotInfo
? 'bg-gradient-to-r from-blue-50 to-cyan-50 dark:from-blue-900/30 dark:to-cyan-900/30 border-2 border-blue-300 dark:border-blue-600'
: 'bg-gradient-to-r from-blue-50 to-purple-50 dark:from-blue-900/20 dark:to-purple-900/20 border-2 border-blue-200 dark:border-blue-700'}`}
>
@@ -47,27 +49,29 @@ const SubscriptionStatusBanner: React.FC<{
<div>
<h3 className="text-lg font-semibold text-[var(--text-primary)] flex items-center gap-2">
<Crown className="w-5 h-5 text-yellow-500" />
{planName} {showTrialInfo && <span className="text-blue-600 dark:text-blue-400">(Prueba Gratis)</span>}
{planName} {showPilotInfo && <span className="text-blue-600 dark:text-blue-400">(Programa Piloto)</span>}
{!showPilotInfo && showTrialInfo && <span className="text-blue-600 dark:text-blue-400">(Prueba Gratis)</span>}
</h3>
<Badge variant={showTrialInfo ? 'info' : status === 'active' ? 'success' : 'default'} className="mt-2">
{showTrialInfo ? `En Prueba (${trialDaysRemaining} días)` : status === 'active' ? 'Activo' : status}
<Badge variant={showPilotInfo ? 'info' : showTrialInfo ? 'info' : status === 'active' ? 'success' : 'default'} className="mt-2">
{showPilotInfo ? 'Piloto Activo' : showTrialInfo ? `En Prueba (${trialDaysRemaining} días)` : status === 'active' ? 'Activo' : status}
</Badge>
</div>
<div className="text-center">
<p className="text-sm text-[var(--text-secondary)]">{showTrialInfo ? 'Fin de la Prueba' : 'Próxima Facturación'}</p>
<p className="font-semibold text-[var(--text-primary)]">{showTrialInfo ? trialEndsAt : nextBilling}</p>
<p className="text-sm text-[var(--text-secondary)]">{showPilotInfo ? 'Fin del Piloto' : showTrialInfo ? 'Fin de la Prueba' : 'Próxima Facturación'}</p>
<p className="font-semibold text-[var(--text-primary)]">{showPilotInfo ? trialEndsAt : showTrialInfo ? trialEndsAt : nextBilling}</p>
</div>
<div className="text-center">
<p className="text-sm text-[var(--text-secondary)]">Costo Mensual</p>
<p className="font-semibold text-[var(--text-primary)] text-lg">
{cost} {showTrialInfo && <span className="text-xs text-blue-600 dark:text-blue-400">(después de la prueba)</span>}
{cost} {showPilotInfo && <span className="text-xs text-blue-600 dark:text-blue-400">(después del periodo piloto)</span>}
{!showPilotInfo && showTrialInfo && <span className="text-xs text-blue-600 dark:text-blue-400">(después de la prueba)</span>}
</p>
</div>
<div className="flex flex-col gap-2">
{showTrialInfo ? (
{showPilotInfo || showTrialInfo ? (
<>
<Button onClick={onUpgrade} variant="primary" size="sm" className="w-full bg-gradient-to-r from-blue-600 to-cyan-600 hover:from-blue-700 hover:to-cyan-700">
<ArrowRight className="w-4 h-4 mr-2" />
@@ -94,9 +98,9 @@ const SubscriptionStatusBanner: React.FC<{
)}
</div>
</div>
{/* Trial Countdown Banner */}
{showTrialInfo && (
{/* Pilot/Trial Countdown Banner */}
{(showPilotInfo || showTrialInfo) && (
<div className="mt-4 p-4 bg-gradient-to-r from-blue-600/10 to-cyan-600/10 border border-blue-300/50 rounded-lg">
<div className="flex items-center gap-3">
<div className="p-2 bg-blue-500/20 rounded-lg border border-blue-500/30 flex-shrink-0">
@@ -104,7 +108,10 @@ const SubscriptionStatusBanner: React.FC<{
</div>
<div className="flex-1">
<p className="text-sm font-medium text-blue-700 dark:text-blue-300">
¡Disfruta de tu periodo de prueba! Tu acceso gratuito termina en <strong>{trialDaysRemaining} días</strong>.
{showPilotInfo
? `¡Eres parte de nuestro programa piloto! Tu acceso gratuito termina en <strong>${trialDaysRemaining} días</strong>.`
: `¡Disfruta de tu periodo de prueba! Tu acceso gratuito termina en <strong>${trialDaysRemaining} días</strong>.`
}
</p>
</div>
<Button onClick={onUpgrade} variant="ghost" size="sm" className="text-blue-600 dark:text-blue-400 hover:bg-blue-500/10">
@@ -632,6 +639,15 @@ const SubscriptionPageRedesign: React.FC = () => {
// Check if there are any high usage metrics
const hasHighUsageMetrics = forecastUsage && forecastUsage.highUsageMetrics && forecastUsage.highUsageMetrics.length > 0;
// Determine if this is a pilot subscription based on characteristics
// Pilot subscriptions have extended trial periods (typically 90 days from PILOT2025 coupon)
// compared to regular trials (typically 14 days), so we check for longer trial periods
const isPilotSubscription = usageSummary.status === 'trialing' &&
usageSummary.trial_ends_at &&
new Date(usageSummary.trial_ends_at) > new Date() &&
// Check if trial period is longer than typical trial (e.g., > 60 days indicates pilot)
(new Date(usageSummary.trial_ends_at).getTime() - new Date().getTime()) > (60 * 24 * 60 * 60 * 1000); // 60+ days
return (
<div className="p-6 space-y-6">
<PageHeader
@@ -643,20 +659,21 @@ const SubscriptionPageRedesign: React.FC = () => {
<SubscriptionStatusBanner
planName={usageSummary.plan.charAt(0).toUpperCase() + usageSummary.plan.slice(1)}
status={usageSummary.status}
nextBilling={new Date(usageSummary.next_billing_date).toLocaleDateString('es-ES', {
day: '2-digit',
month: '2-digit',
year: 'numeric'
nextBilling={new Date(usageSummary.next_billing_date).toLocaleDateString('es-ES', {
day: '2-digit',
month: '2-digit',
year: 'numeric'
})}
cost={subscriptionService.formatPrice(usageSummary.monthly_price)}
onUpgrade={() => setShowPlans(true)}
onManagePayment={() => setPaymentMethodModalOpen(true)}
showUpgradeButton={usageSummary.plan !== 'enterprise'}
isTrial={usageSummary.status === 'trialing'}
trialEndsAt={usageSummary.trial_ends_at ? new Date(usageSummary.trial_ends_at).toLocaleDateString('es-ES', {
day: '2-digit',
month: '2-digit',
year: 'numeric'
isTrial={usageSummary.status === 'trialing' || isPilotSubscription}
isPilot={isPilotSubscription}
trialEndsAt={usageSummary.trial_ends_at ? new Date(usageSummary.trial_ends_at).toLocaleDateString('es-ES', {
day: '2-digit',
month: '2-digit',
year: 'numeric'
}) : undefined}
trialDaysRemaining={usageSummary.trial_ends_at ? Math.max(0, Math.ceil((new Date(usageSummary.trial_ends_at).getTime() - new Date().getTime()) / (1000 * 60 * 60 * 24))) : undefined}
/>