Files
app_umbrix/app/plans/page.tsx

258 lines
8.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client';
import { useState } from 'react';
import { ArrowLeft, Check } from 'lucide-react';
import { useRouter } from 'next/navigation';
export default function Plans() {
const router = useRouter();
const [isLoading, setIsLoading] = useState(false);
const handlePurchase = async (planType: string) => {
// Проверяем есть ли уже активная подписка ЧЕРЕЗ API
const telegramWebApp = (window as any).Telegram?.WebApp;
const telegramId = telegramWebApp?.initDataUnsafe?.user?.id;
const telegramUsername = telegramWebApp?.initDataUnsafe?.user?.username;
if (telegramId || telegramUsername) {
const params = new URLSearchParams();
if (telegramId) params.append('telegramId', telegramId.toString());
if (telegramUsername) params.append('telegramUsername', telegramUsername);
const checkResponse = await fetch(`/api/user-subscription?${params.toString()}`);
const checkData = await checkResponse.json();
if (checkData.success && checkData.hasSubscription) {
const confirmOverwrite = confirm('У вас уже есть активная подписка. Создать новую? (старая будет заменена)');
if (!confirmOverwrite) {
return;
}
}
}
setIsLoading(true);
try {
const telegramWebApp = (window as any).Telegram?.WebApp;
console.log('🔍 Telegram WebApp объект:', telegramWebApp);
console.log('🔍 initData:', telegramWebApp?.initData);
console.log('🔍 initDataUnsafe (FULL):', JSON.stringify(telegramWebApp?.initDataUnsafe, null, 2));
console.log('🔍 user (FULL):', JSON.stringify(telegramWebApp?.initDataUnsafe?.user, null, 2));
const user = telegramWebApp?.initDataUnsafe?.user;
const telegramId = user?.id || null;
const telegramUsername = user?.username || null;
const firstName = user?.first_name || null;
const lastName = user?.last_name || null;
console.log('📤 Отправляем:', { planType, telegramId, telegramUsername, firstName, lastName });
// Вызываем API для создания реального пользователя в Marzban
const response = await fetch('/api/create-user', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
planType: planType,
telegramId: telegramId,
telegramUsername: telegramUsername,
firstName: firstName,
lastName: lastName,
}),
});
const data = await response.json();
if (!data.success) {
throw new Error(data.error || 'Failed to create subscription');
}
// Просто возвращаемся на главную - там данные обновятся автоматически
router.push('/');
} catch (error) {
console.error('Purchase error:', error);
alert('Ошибка при создании подписки. Попробуйте позже.');
} finally {
setIsLoading(false);
}
};
return (
<div
className="min-h-screen"
style={{ background: 'var(--bg-app)', color: 'var(--text-primary)' }}
>
{/* Header */}
<header
className="flex items-center gap-3 p-4 border-b sticky top-0 z-10 backdrop-blur-sm"
style={{ borderColor: 'var(--border)', background: 'var(--bg-card)' }}
>
<button onClick={() => router.push('/')} className="p-2 hover:bg-slate-700 rounded-lg transition-colors">
<ArrowLeft className="w-6 h-6" />
</button>
<h1
className="text-xl font-bold"
style={{ color: 'var(--text-white)' }}
>
Выбрать тариф
</h1>
</header>
<main className="p-4">
{/* Trial - полная ширина */}
<div className="mb-3">
<PlanCard
badge="🎁 Пробный период"
title="7 дней бесплатно"
price="0₽"
features={[
'Все тарифы доступны',
'Безлимитный трафик',
'Любые локации',
]}
buttonText="Попробовать"
isPrimary
onPurchase={() => handlePurchase('trial')}
isLoading={isLoading}
/>
</div>
{/* Grid 2x2 для остальных тарифов */}
<div className="grid grid-cols-2 gap-3">
{/* Start */}
<PlanCard
badge="🌍 Старт"
title="Базовый"
price="100₽/мес"
features={['1 устройство', '1 локация', '50 ГБ']}
buttonText="Выбрать"
onPurchase={() => handlePurchase('start')}
isLoading={isLoading}
/>
{/* Plus */}
<PlanCard
badge="🌎 Плюс"
title="Расширенный"
price="299₽/мес"
features={['3 устройства', '3 локации', '299 ГБ']}
buttonText="Выбрать"
onPurchase={() => handlePurchase('plus')}
isLoading={isLoading}
/>
{/* Max */}
<PlanCard
badge="🌏 Макс"
title="Премиум"
price="350₽/мес"
features={['5 устройств', '15+ стран', 'Безлимит']}
buttonText="Выбрать"
isPopular
onPurchase={() => handlePurchase('max')}
isLoading={isLoading}
/>
{/* Empty slot or promo */}
<div
className="p-4 rounded-xl border flex items-center justify-center"
style={{
background: 'var(--bg-card)',
borderColor: 'var(--border)',
borderStyle: 'dashed',
}}
>
<div className="text-center opacity-50">
<div className="text-2xl mb-1">💰</div>
<div className="text-xs">Скоро новые</div>
<div className="text-xs">тарифы</div>
</div>
</div>
</div>
</main>
</div>
);
}
function PlanCard({
badge,
title,
price,
features,
buttonText,
isPrimary = false,
isPopular = false,
onPurchase,
isLoading = false,
}: {
badge: string;
title: string;
price: string;
features: string[];
buttonText: string;
isPrimary?: boolean;
isPopular?: boolean;
onPurchase: () => void;
isLoading?: boolean;
}) {
return (
<div
className="p-3 rounded-xl border relative"
style={{
background: 'var(--bg-card)',
borderColor: isPrimary
? 'var(--primary)'
: isPopular
? 'var(--primary)'
: 'var(--border)',
}}
>
{isPopular && (
<div
className="absolute -top-2 -right-2 px-2 py-0.5 rounded-full text-xs font-bold"
style={{ background: 'var(--primary)', color: 'var(--text-white)' }}
>
ТОП
</div>
)}
<div className="text-xs mb-1 opacity-70">{badge}</div>
<h3
className="font-bold mb-1 text-sm"
style={{ color: 'var(--text-white)' }}
>
{title}
</h3>
<div
className="text-xl font-bold mb-2"
style={{ color: 'var(--primary)' }}
>
{price}
</div>
<ul className="space-y-1.5 mb-3">
{features.map((feature, i) => (
<li key={i} className="flex items-center gap-1.5 text-xs">
<Check
className="w-3.5 h-3.5 flex-shrink-0"
style={{ color: 'var(--success)' }}
/>
<span>{feature}</span>
</li>
))}
</ul>
<button
onClick={onPurchase}
disabled={isLoading}
className="w-full py-2 rounded-lg font-semibold text-xs transition-all hover:opacity-90 disabled:opacity-50 disabled:cursor-not-allowed"
style={{
background: isPrimary ? 'var(--primary)' : 'var(--bg-elevated)',
color: 'var(--text-white)',
}}
>
{isLoading ? 'Оформление...' : buttonText}
</button>
</div>
);
}