Files
bedolaga-cabinet/src/components/subscription/PurchaseCTAButton.tsx
c0mrade debee7729f fix: platform-aware delete confirmation + trial CTA to purchase
Delete subscription:
- Telegram mini app: native destructive popup (red button)
- Web (mobile + desktop): Sheet bottom panel with full-width buttons
- Both: proper loading state on delete button

Trial CTA: leads to /subscription/purchase (trial cannot be renewed)
2026-03-24 18:30:59 +03:00

116 lines
4.1 KiB
TypeScript

import { Link } from 'react-router';
import { useTranslation } from 'react-i18next';
import { HoverBorderGradient } from '../ui/hover-border-gradient';
import type { Subscription } from '../../types';
interface PurchaseCTAButtonProps {
subscription: Subscription | null;
/** In multi-tariff mode, link to /subscriptions/:id/renew instead of /subscription/purchase */
isMultiTariff?: boolean;
}
export default function PurchaseCTAButton({
subscription,
isMultiTariff = false,
}: PurchaseCTAButtonProps) {
const { t } = useTranslation();
const isExpired = !subscription || (!subscription.is_active && !subscription.is_trial);
const isTrial = subscription?.is_trial;
const isDaily = subscription?.is_daily;
// Daily tariffs renew automatically — no manual renewal button needed in multi-tariff
if (isMultiTariff && isDaily && !isExpired) return null;
const accentColor = isExpired ? '#FF3B5C' : 'rgb(var(--color-accent-400))';
const buttonText = isExpired
? t('subscription.getSubscription')
: isTrial
? t('subscription.trialUpgrade.title')
: t('subscription.extend');
const hintText = isExpired
? t('subscription.cta.expiredHint')
: isTrial
? t('subscription.cta.trialHint')
: isMultiTariff
? t('subscription.cta.renewHint', 'Продление подписки')
: t('subscription.cta.activeHint');
// Trial → purchase page (buy a real tariff, trial can't be renewed)
// Multi-tariff active → per-subscription renew page
// Otherwise → purchase page
const linkTo = isTrial
? '/subscription/purchase'
: isMultiTariff && subscription?.id
? `/subscriptions/${subscription.id}/renew`
: '/subscription/purchase';
return (
<Link to={linkTo} className="block">
<HoverBorderGradient
accentColor={accentColor}
duration={4}
className="group relative w-full cursor-pointer overflow-hidden rounded-2xl"
>
<div
className="relative flex items-center justify-between rounded-[14px] px-5 py-4 transition-colors duration-300"
style={{
background: isExpired
? 'linear-gradient(135deg, rgba(255,59,92,0.08), rgba(255,107,53,0.06))'
: 'linear-gradient(135deg, rgba(var(--color-accent-400), 0.08), rgba(var(--color-accent-400), 0.06))',
}}
>
{/* Left: icon + text */}
<div className="flex items-center gap-3">
{/* Sparkle icon */}
<div
className="flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-xl"
style={{
background: isExpired
? 'rgba(255,59,92,0.12)'
: 'rgba(var(--color-accent-400), 0.12)',
}}
>
<svg
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke={accentColor}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
>
<path d="M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09z" />
</svg>
</div>
<div>
<div className="text-[15px] font-semibold text-dark-50">{buttonText}</div>
<div className="text-[12px] text-dark-50/40">{hintText}</div>
</div>
</div>
{/* Right: chevron */}
<svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
className="flex-shrink-0 text-dark-50/30 transition-transform duration-300 group-hover:translate-x-1"
>
<path d="M9 18l6-6-6-6" />
</svg>
</div>
</HoverBorderGradient>
</Link>
);
}