157 lines
7.0 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.

import {
getSubscription,
getSubscriptionPrices,
getSubscriptions,
} from '@/actions/api/subscriptions';
import { getSessionUser } from '@/actions/session';
import { TryFreeButton } from '@/components/subscription';
import { env } from '@/config/env';
import { Enum_Subscriptionprice_Period as SubscriptionPricePeriod } from '@repo/graphql/types';
import { Button } from '@repo/ui/components/ui/button';
import { formatMoney } from '@repo/utils/money';
import { ArrowRight, Crown, Infinity as InfinityIcon } from 'lucide-react';
import Link from 'next/link';
export default async function ProPage() {
const { telegramId } = await getSessionUser();
const { subscriptions } = await getSubscriptions({
filters: { customer: { telegramId: { eq: telegramId } } },
});
const hasActiveSubscription = subscriptions?.length
? ((await getSubscription({ telegramId }))?.hasActiveSubscription ?? false)
: false;
const canUseTrial = !subscriptions?.length;
const { subscriptionPrices = [] } = await getSubscriptionPrices({
filters: {
active: { eq: true },
period: { ne: SubscriptionPricePeriod.Trial },
},
});
const botUrl = new URL(env.BOT_URL);
botUrl.searchParams.set('start', 'pro');
return (
<div className="min-h-screen bg-gradient-to-br from-slate-50 via-blue-50 to-indigo-100 dark:from-slate-900 dark:via-slate-800 dark:to-slate-900">
{/* Hero Section */}
<div className="px-4 py-8 sm:px-6 lg:px-8">
<div className="mx-auto max-w-4xl text-center">
<div className="mb-2 flex justify-center">
<div className="relative">
<div className="absolute inset-0 rounded-full bg-gradient-to-r from-purple-600 to-blue-600 opacity-30 blur-xl dark:from-purple-700 dark:to-blue-700" />
<div className="relative rounded-full bg-gradient-to-r from-purple-600 to-blue-600 p-4 dark:from-purple-700 dark:to-blue-700">
<Crown className="size-8 text-white" />
</div>
</div>
</div>
<h1 className="mb-4 text-4xl font-bold tracking-tight text-gray-900 dark:text-white sm:text-6xl">
<span className="bg-gradient-to-r from-purple-600 to-blue-600 bg-clip-text text-transparent dark:from-purple-700 dark:to-blue-700">
Pro
</span>{' '}
Доступ
</h1>
<p className="mx-auto mb-6 max-w-2xl text-xl text-gray-600 dark:text-gray-300">
{hasActiveSubscription
? 'Ваш Pro доступ активен!'
: 'Разблокируйте больше возможностей'}
</p>
{!hasActiveSubscription && (
<div className="flex flex-col items-center justify-center gap-4 sm:flex-row">
{canUseTrial && <TryFreeButton />}
<Button
asChild
className={`w-full border-2 text-base font-semibold sm:w-auto ${
canUseTrial
? 'border-gray-300 text-gray-700 hover:bg-gray-100 dark:border-gray-600 dark:text-gray-300 dark:hover:bg-gray-700'
: 'border-0 bg-gradient-to-r from-purple-600 to-blue-600 text-white hover:from-purple-700 hover:to-blue-700 dark:from-purple-700 dark:to-blue-700 dark:hover:from-purple-800 dark:hover:to-blue-800'
}`}
size="lg"
variant={canUseTrial ? 'outline' : 'default'}
>
<Link href={botUrl.toString()} rel="noopener noreferrer" target="_blank">
Приобрести Pro доступ через бота
<ArrowRight className="ml-2 size-5" />
</Link>
</Button>
</div>
)}
<div className="mx-auto mt-12 max-w-2xl">
<h2 className="mb-4 text-center text-2xl font-bold text-gray-900 dark:text-white">
Преимущества
</h2>
<div className="space-y-4">
<div className="flex items-start gap-3 rounded-lg border border-gray-200 bg-white/50 p-4 dark:border-gray-700 dark:bg-slate-800/50">
<div className="mt-1 shrink-0">
<InfinityIcon className="size-5 text-purple-600 dark:text-purple-400" />
</div>
<p className="text-left text-base leading-relaxed text-gray-700 dark:text-gray-300">
Доступно неограниченное количество записей в месяц
</p>
</div>
{/* <div className="flex items-start gap-3 rounded-lg border border-gray-200 bg-white/50 p-4 dark:border-gray-700 dark:bg-slate-800/50">
<div className="mt-1 shrink-0">
<Star className="size-5 text-purple-600 dark:text-purple-400" />
</div>
<p className="text-left text-base leading-relaxed text-gray-700 dark:text-gray-300">
Профиль и аватар выделяются цветом
</p>
</div> */}
</div>
</div>
{subscriptionPrices?.length > 0 && (
<div className="mx-auto mt-12 max-w-2xl">
<h2 className="mb-4 text-center text-2xl font-bold text-gray-900 dark:text-white">
Цены
</h2>
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
{subscriptionPrices.map((price) => (
<div
className={`relative rounded-xl border bg-white/60 p-4 text-left dark:bg-slate-800/60 ${
price?.period === SubscriptionPricePeriod.Month
? 'border-2 border-purple-400'
: 'border-gray-200 dark:border-gray-700'
}`}
key={price?.documentId}
>
{price?.period === SubscriptionPricePeriod.Month && (
<div className="absolute -top-2 right-3 rounded-full bg-purple-600 px-2 py-0.5 text-xs font-semibold text-white dark:bg-purple-500">
Популярный
</div>
)}
<div className="flex items-baseline justify-between">
<div className="text-xl font-bold text-gray-900 dark:text-white">
{formatMoney(price?.amount ?? 0)}
</div>
{typeof price?.days === 'number' && (
<div className="text-sm text-gray-600 dark:text-gray-300">
{price.days} дн.
</div>
)}
</div>
{price?.description && (
<div className="mt-2 text-sm text-gray-600 dark:text-gray-300">
{price.description}
</div>
)}
</div>
))}
</div>
</div>
)}
</div>
</div>
</div>
);
}