Files
deals24togo_fe/src/pages/SubscriptionPage.tsx
2026-03-06 23:17:30 +00:00

146 lines
5.7 KiB
TypeScript

import React, { useEffect, useState } from 'react';
import { Link } from 'react-router-dom';
import { CreditCard, CheckCircle, Clock } from 'lucide-react';
import { api } from '../services/api';
import { Subscription } from '../types';
import { useI18n } from '../contexts/I18nContext';
import { usePageTitle } from '../hooks/usePageTitle';
import { useToast } from '../contexts/ToastContext';
import Button from '../components/common/Button';
import Card, { CardContent, CardHeader } from '../components/common/Card';
interface SubscriptionStatus {
has_active_subscription: boolean;
subscription: Subscription | null;
}
const SubscriptionPage: React.FC = () => {
const { t } = useI18n();
usePageTitle('Subscription');
const { showToast } = useToast();
const [status, setStatus] = useState<SubscriptionStatus | null>(null);
const [loading, setLoading] = useState(true);
const [initiating, setInitiating] = useState<string | null>(null);
useEffect(() => {
api.subscriptions.me()
.then((data: any) => setStatus(data))
.catch(() => {})
.finally(() => setLoading(false));
}, []);
const handleSubscribe = async (plan: 'monthly' | 'yearly') => {
setInitiating(plan);
try {
const result = await api.payments.initiate({ type: 'subscription', plan }) as any;
window.location.href = result.payment_url;
} catch (err: any) {
showToast(err.message || 'Failed to initiate payment', 'error');
setInitiating(null);
}
};
const formatter = new Intl.NumberFormat('fr-TG', {
style: 'currency',
currency: 'XOF',
minimumFractionDigits: 0,
});
return (
<div className="max-w-3xl mx-auto px-4 sm:px-6 lg:px-8 py-10">
<div className="flex items-center gap-3 mb-8">
<CreditCard className="h-7 w-7 text-accent-600" />
<h1 className="text-3xl font-bold text-primary-800">{t.subscription.title}</h1>
</div>
{/* Current status */}
{loading ? (
<div className="mb-8 p-4 bg-gray-50 border border-gray-200 rounded-lg animate-pulse h-16" />
) : status?.has_active_subscription && status.subscription ? (
<div className="mb-8 p-4 bg-success-50 border border-success-200 rounded-lg flex items-start gap-3">
<CheckCircle className="h-5 w-5 text-success-600 mt-0.5 flex-shrink-0" />
<div>
<p className="font-medium text-success-800">
{t.subscription.activePlan}:{' '}
{status.subscription.plan === 'monthly' ? t.subscription.monthly : t.subscription.yearly}
</p>
<p className="text-sm text-success-700 mt-0.5">
{t.subscription.activeUntil}{' '}
{new Date(status.subscription.ends_at).toLocaleDateString('fr-TG')}
</p>
</div>
</div>
) : (
<div className="mb-8 p-4 bg-warning-50 border border-warning-200 rounded-lg flex items-start gap-3">
<Clock className="h-5 w-5 text-warning-600 mt-0.5 flex-shrink-0" />
<div>
<p className="font-medium text-warning-800">{t.subscription.noSubscription}</p>
<p className="text-sm text-warning-700 mt-0.5">{t.subscription.noSubscriptionDesc}</p>
</div>
</div>
)}
{/* Plan cards */}
<h2 className="text-xl font-semibold text-primary-800 mb-4">{t.subscription.choosePlan}</h2>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-6">
{/* Monthly */}
<Card className="border-2 border-gray-200 hover:border-accent-400 transition-colors">
<CardHeader>
<h3 className="text-lg font-bold text-primary-800">{t.subscription.monthly}</h3>
</CardHeader>
<CardContent>
<p className="text-3xl font-bold text-accent-700 mb-1">
{formatter.format(1000)}
</p>
<p className="text-sm text-primary-500 mb-4">{t.subscription.perMonth}</p>
<p className="text-sm text-primary-600 mb-6">{t.subscription.monthlyDesc}</p>
<Button
variant="secondary"
className="w-full"
disabled={initiating !== null}
onClick={() => handleSubscribe('monthly')}
>
{initiating === 'monthly' ? t.payment.processing : t.subscription.subscribe}
</Button>
</CardContent>
</Card>
{/* Yearly */}
<Card className="border-2 border-accent-400 relative">
<div className="absolute -top-3 left-1/2 -translate-x-1/2">
<span className="bg-accent-500 text-white text-xs font-bold px-3 py-1 rounded-full">
{t.subscription.saveMonths}
</span>
</div>
<CardHeader>
<h3 className="text-lg font-bold text-primary-800">{t.subscription.yearly}</h3>
</CardHeader>
<CardContent>
<p className="text-3xl font-bold text-accent-700 mb-1">
{formatter.format(10000)}
</p>
<p className="text-sm text-primary-500 mb-4">{t.subscription.perYear}</p>
<p className="text-sm text-primary-600 mb-6">{t.subscription.yearlyDesc}</p>
<Button
variant="secondary"
className="w-full"
disabled={initiating !== null}
onClick={() => handleSubscribe('yearly')}
>
{initiating === 'yearly' ? t.payment.processing : t.subscription.subscribe}
</Button>
</CardContent>
</Card>
</div>
<p className="mt-6 text-center text-sm text-primary-500">
<Link to="/agency/dashboard" className="text-accent-600 hover:underline">
Back to Dashboard
</Link>
</p>
</div>
);
};
export default SubscriptionPage;