106 lines
5.3 KiB
JavaScript
106 lines
5.3 KiB
JavaScript
import React from 'react'
|
|
import { Link } from '@inertiajs/react'
|
|
import AccessBadge from './AccessBadge'
|
|
|
|
function ActionButton({ disabled, children, onClick, href, tone = 'primary' }) {
|
|
const toneClass = {
|
|
primary: 'border-sky-300/25 bg-sky-300/12 text-sky-100 hover:border-sky-300/40 hover:bg-sky-300/18',
|
|
emerald: 'border-emerald-300/25 bg-emerald-300/10 text-emerald-100 hover:bg-emerald-300/18',
|
|
default: 'border-white/10 bg-white/[0.05] text-white hover:border-white/20 hover:bg-white/[0.08]',
|
|
}[tone] ?? 'border-white/10 bg-white/[0.05] text-white hover:border-white/20 hover:bg-white/[0.08]'
|
|
|
|
if (href) {
|
|
return <Link href={href} className={`inline-flex w-full items-center justify-center rounded-full border px-5 py-3 text-sm font-semibold transition ${toneClass}`}>{children}</Link>
|
|
}
|
|
|
|
return (
|
|
<button type="button" disabled={disabled} onClick={onClick} className={`inline-flex w-full items-center justify-center rounded-full border px-5 py-3 text-sm font-semibold transition disabled:cursor-not-allowed disabled:opacity-60 ${toneClass}`}>
|
|
{children}
|
|
</button>
|
|
)
|
|
}
|
|
|
|
export default function PlanCard({ product, selectedPlan, currentTier, isSubscribed, activePlanKey, billingEnabled, loginHref, manageHref, onCheckout }) {
|
|
const activeTier = typeof currentTier === 'string' ? currentTier.toLowerCase() : 'free'
|
|
const isActivePlan = selectedPlan?.key === activePlanKey
|
|
// Pro subscribers already have creator access — don't show a separate "switch" CTA for creator card
|
|
const isHigherTierCovered = activeTier === 'pro' && product.tier === 'creator'
|
|
const isPlanReady = Boolean(selectedPlan?.configured && selectedPlan?.price_id_valid && selectedPlan?.remote_price_exists !== false)
|
|
// User has a different active subscription (not this plan)
|
|
const isSubscribedElsewhere = isSubscribed && !isActivePlan
|
|
|
|
return (
|
|
<article className={`relative overflow-hidden rounded-[32px] border p-6 transition md:p-7 ${
|
|
isActivePlan
|
|
? 'border-emerald-300/25 bg-[linear-gradient(180deg,rgba(16,185,129,0.1),rgba(15,23,42,0.96))] shadow-[0_28px_90px_rgba(5,150,105,0.14)]'
|
|
: product.featured
|
|
? 'border-sky-300/25 bg-[linear-gradient(180deg,rgba(14,165,233,0.12),rgba(15,23,42,0.96))] shadow-[0_28px_90px_rgba(2,132,199,0.14)]'
|
|
: 'border-white/10 bg-white/[0.04]'
|
|
}`}>
|
|
<div className="absolute inset-x-0 top-0 h-px bg-[linear-gradient(90deg,transparent,rgba(255,255,255,0.45),transparent)]" />
|
|
<div className="flex items-start justify-between gap-4">
|
|
<div>
|
|
<p className="text-[11px] font-semibold uppercase tracking-[0.22em] text-slate-400">{product.badge}</p>
|
|
<h2 className="mt-3 text-3xl font-semibold tracking-[-0.05em] text-white">{product.name}</h2>
|
|
<p className="mt-3 text-sm leading-7 text-slate-300">{product.description}</p>
|
|
</div>
|
|
<div className="flex shrink-0 flex-col items-end gap-2">
|
|
{isActivePlan
|
|
? <span className="rounded-full border border-emerald-300/30 bg-emerald-300/14 px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.18em] text-emerald-100">Your plan</span>
|
|
: <AccessBadge tier={product.tier} />}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="mt-6 rounded-[24px] border border-white/10 bg-black/20 px-4 py-4">
|
|
<p className="text-[10px] font-semibold uppercase tracking-[0.2em] text-slate-400">Monthly</p>
|
|
<p className="mt-3 text-3xl font-semibold tracking-[-0.04em] text-white">{selectedPlan?.price_display || '—'}</p>
|
|
<p className="mt-1 text-xs uppercase tracking-[0.18em] text-slate-500">Billed monthly · cancel anytime</p>
|
|
</div>
|
|
|
|
<div className="mt-6 space-y-3 text-sm text-slate-300">
|
|
{product.features.map((feature) => (
|
|
<div key={feature} className="flex items-start gap-2.5 rounded-2xl border border-white/10 bg-black/20 px-4 py-3">
|
|
<span className="mt-px shrink-0 text-emerald-400">✓</span>
|
|
<span>{feature}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
<div className="mt-6 space-y-3">
|
|
{/* Active plan: manage */}
|
|
{isActivePlan ? (
|
|
<ActionButton href={manageHref} tone="emerald">Manage subscription</ActionButton>
|
|
) : null}
|
|
|
|
{/* Subscribed elsewhere: switch */}
|
|
{isSubscribedElsewhere && !isHigherTierCovered ? (
|
|
<ActionButton href={manageHref} tone="default">Switch to {product.name}</ActionButton>
|
|
) : null}
|
|
|
|
{/* Higher tier already covers this plan */}
|
|
{isHigherTierCovered && !isActivePlan ? (
|
|
<p className="text-center text-xs text-slate-500">Included in your Pro plan</p>
|
|
) : null}
|
|
|
|
{/* Not subscribed, not logged in */}
|
|
{!isSubscribed && loginHref ? (
|
|
<ActionButton href={loginHref} tone="primary">
|
|
{billingEnabled ? `Get ${product.name}` : 'Coming soon'}
|
|
</ActionButton>
|
|
) : null}
|
|
|
|
{/* Not subscribed, logged in */}
|
|
{!isSubscribed && !loginHref ? (
|
|
<ActionButton
|
|
disabled={!billingEnabled || !isPlanReady}
|
|
onClick={() => onCheckout(selectedPlan)}
|
|
tone="primary"
|
|
>
|
|
{!billingEnabled ? 'Coming soon' : isPlanReady ? `Get ${product.name} — ${selectedPlan?.price_display || ''}` : 'Not available yet'}
|
|
</ActionButton>
|
|
) : null}
|
|
</div>
|
|
</article>
|
|
)
|
|
}
|