feat(payment): add test mode check for payment callback IP validation
This commit is contained in:
@@ -249,6 +249,8 @@ export default function SubscriptionPage() {
|
||||
key={plan.uuid}
|
||||
plan={plan}
|
||||
currentPlanName={my?.plan.name ?? 'free'}
|
||||
currentPlanLevel={my?.plan.level ?? 0}
|
||||
currentPlanActive={!!my && (my.days_remaining ?? 0) > 0}
|
||||
usedTrial={usedTrial}
|
||||
onPurchase={(period) => setPurchaseTarget({ period, planName: plan.name })}
|
||||
onTrial={() => trialMutation.mutate()}
|
||||
@@ -378,6 +380,8 @@ export default function SubscriptionPage() {
|
||||
function PlanCard({
|
||||
plan,
|
||||
currentPlanName,
|
||||
currentPlanLevel,
|
||||
currentPlanActive,
|
||||
usedTrial,
|
||||
onPurchase,
|
||||
onTrial,
|
||||
@@ -385,14 +389,16 @@ function PlanCard({
|
||||
}: {
|
||||
plan: SubscriptionPlan;
|
||||
currentPlanName: string;
|
||||
currentPlanLevel: number;
|
||||
currentPlanActive: boolean;
|
||||
usedTrial: boolean;
|
||||
onPurchase: (period: SubscriptionPeriod) => void;
|
||||
onTrial: () => void;
|
||||
trialPending: boolean;
|
||||
}) {
|
||||
const meta = PLAN_META[plan.name] ?? PLAN_META.free;
|
||||
const isCurrent = plan.name === currentPlanName;
|
||||
const isUpgrade = (plan.level ?? 0) > ((PLAN_META[currentPlanName] ? plan.level : 0));
|
||||
const meta = PLAN_META[plan.name] ?? PLAN_META.free;
|
||||
const isCurrent = plan.name === currentPlanName;
|
||||
const isDowngrade = currentPlanActive && (plan.level ?? 0) < currentPlanLevel;
|
||||
const paidPeriods = plan.periods.filter((p) => !p.is_trial);
|
||||
const trialPeriod = plan.periods.find((p) => p.is_trial);
|
||||
const Icon = meta.icon;
|
||||
@@ -484,7 +490,7 @@ function PlanCard({
|
||||
</ul>
|
||||
|
||||
{/* تریال */}
|
||||
{trialPeriod && !usedTrial && plan.level > 0 && (
|
||||
{trialPeriod && !usedTrial && plan.level > 0 && !isDowngrade && (
|
||||
<div style={{
|
||||
marginTop: 14, padding: '10px 12px', borderRadius: 'var(--r-sm)',
|
||||
background: 'linear-gradient(135deg, #eff6ff, #f5f3ff)',
|
||||
@@ -510,31 +516,46 @@ function PlanCard({
|
||||
{/* دورههای پرداختی */}
|
||||
{paidPeriods.length > 0 && (
|
||||
<div style={{ padding: '14px 20px', display: 'flex', flexDirection: 'column', gap: 8 }}>
|
||||
{isDowngrade && (
|
||||
<div style={{
|
||||
display: 'flex', alignItems: 'center', gap: 8,
|
||||
padding: '10px 12px', borderRadius: 'var(--r-sm)',
|
||||
background: '#fef9c3', border: '1px solid #fbbf24',
|
||||
fontSize: 12.5, color: '#92400e', marginBottom: 2,
|
||||
}}>
|
||||
<span style={{ fontSize: 15 }}>🔒</span>
|
||||
<span>تا پایان اشتراک فعلی قابل انتخاب نیست</span>
|
||||
</div>
|
||||
)}
|
||||
{paidPeriods.map((period) => (
|
||||
<div key={period.uuid} style={{
|
||||
display: 'flex', alignItems: 'center', justifyContent: 'space-between',
|
||||
gap: 8, padding: '8px 10px', borderRadius: 'var(--r-sm)',
|
||||
border: '1px solid var(--border)', background: 'var(--surface-2)',
|
||||
border: '1px solid var(--border)',
|
||||
background: isDowngrade ? 'var(--surface-3)' : 'var(--surface-2)',
|
||||
opacity: isDowngrade ? 0.6 : 1,
|
||||
}}>
|
||||
<div>
|
||||
<div style={{ fontSize: 13, fontWeight: 600, color: 'var(--text)' }}>{period.label}</div>
|
||||
<div style={{ fontSize: 11.5, color: 'var(--text-3)' }}>{period.duration_months} ماه</div>
|
||||
</div>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
||||
<span style={{ fontWeight: 700, fontSize: 13.5, color: meta.color }}>
|
||||
<span style={{ fontWeight: 700, fontSize: 13.5, color: isDowngrade ? 'var(--text-3)' : meta.color }}>
|
||||
{formatRial(period.price_rials)}
|
||||
</span>
|
||||
<button
|
||||
onClick={() => onPurchase(period)}
|
||||
disabled={isDowngrade}
|
||||
onClick={() => !isDowngrade && onPurchase(period)}
|
||||
style={{
|
||||
padding: '6px 14px', borderRadius: 'var(--r-sm)', cursor: 'pointer',
|
||||
background: isCurrent ? 'var(--surface)' : meta.color,
|
||||
color: isCurrent ? meta.color : '#fff',
|
||||
border: `1.5px solid ${meta.color}`,
|
||||
padding: '6px 14px', borderRadius: 'var(--r-sm)',
|
||||
cursor: isDowngrade ? 'not-allowed' : 'pointer',
|
||||
background: isDowngrade ? 'var(--surface-3)' : isCurrent ? 'var(--surface)' : meta.color,
|
||||
color: isDowngrade ? 'var(--text-3)' : isCurrent ? meta.color : '#fff',
|
||||
border: `1.5px solid ${isDowngrade ? 'var(--border)' : meta.color}`,
|
||||
fontSize: 12.5, fontWeight: 700, transition: '.14s',
|
||||
fontFamily: 'inherit',
|
||||
}}
|
||||
onMouseEnter={(e) => { (e.currentTarget as HTMLElement).style.opacity = '.85'; }}
|
||||
onMouseEnter={(e) => { if (!isDowngrade) (e.currentTarget as HTMLElement).style.opacity = '.85'; }}
|
||||
onMouseLeave={(e) => { (e.currentTarget as HTMLElement).style.opacity = '1'; }}
|
||||
>
|
||||
{isCurrent ? 'تمدید' : 'خرید'}
|
||||
|
||||
Reference in New Issue
Block a user