mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-30 02:23:47 +00:00
feat: add LIMITED subscription status support with traffic-exhausted UX
- Add is_limited to Subscription type - Show yellow traffic-exhausted badge on Subscription and AdminUsers pages - SubscriptionCardExpired: amber theme with warning icon and buy-traffic CTA for limited - Dashboard: route limited subscriptions to SubscriptionCardExpired - Subscription page: show additional options (buy traffic) for limited subs - Use is_limited boolean instead of status string comparison - Add trafficLimited translations for ru, en, zh, fa - AdminUserDetail StatusBadge: add limited yellow styling
This commit is contained in:
@@ -119,6 +119,7 @@ function StatusBadge({ status }: { status: string }) {
|
||||
deleted: 'bg-dark-600 text-dark-400 border-dark-500',
|
||||
trial: 'bg-accent-500/20 text-accent-400 border-accent-500/30',
|
||||
expired: 'bg-warning-500/20 text-warning-400 border-warning-500/30',
|
||||
limited: 'bg-yellow-500/20 text-yellow-400 border-yellow-500/30',
|
||||
disabled: 'bg-dark-600 text-dark-400 border-dark-500',
|
||||
};
|
||||
|
||||
|
||||
@@ -147,14 +147,18 @@ function UserRow({ user, onClick, formatAmount }: UserRowProps) {
|
||||
? 'border-success-500/30 bg-success-500/20 text-success-400'
|
||||
: user.subscription_status === 'trial'
|
||||
? 'border-accent-500/30 bg-accent-500/20 text-accent-400'
|
||||
: 'border-warning-500/30 bg-warning-500/20 text-warning-400'
|
||||
: user.subscription_status === 'limited'
|
||||
? 'border-yellow-500/30 bg-yellow-500/20 text-yellow-400'
|
||||
: 'border-warning-500/30 bg-warning-500/20 text-warning-400'
|
||||
}`}
|
||||
>
|
||||
{user.subscription_status === 'active'
|
||||
? t('admin.users.status.subscription')
|
||||
: user.subscription_status === 'trial'
|
||||
? t('admin.users.status.trial')
|
||||
: t('admin.users.status.expired')}
|
||||
: user.subscription_status === 'limited'
|
||||
? t('subscription.trafficLimited')
|
||||
: t('admin.users.status.expired')}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -247,7 +247,9 @@ export default function Dashboard() {
|
||||
<div className="skeleton h-12 w-full rounded-xl" />
|
||||
</div>
|
||||
</div>
|
||||
) : subscription?.is_expired || subscription?.status === 'disabled' ? (
|
||||
) : subscription?.is_expired ||
|
||||
subscription?.status === 'disabled' ||
|
||||
subscription?.is_limited ? (
|
||||
<SubscriptionCardExpired
|
||||
subscription={subscription}
|
||||
balanceKopeks={balanceData?.balance_kopeks ?? 0}
|
||||
|
||||
@@ -518,23 +518,76 @@ export default function Subscription() {
|
||||
style={{
|
||||
background: subscription.is_active
|
||||
? `${zone.mainHex}15`
|
||||
: 'rgba(255,59,92,0.12)',
|
||||
: subscription.is_limited
|
||||
? 'rgba(255,184,0,0.12)'
|
||||
: 'rgba(255,59,92,0.12)',
|
||||
border: subscription.is_active
|
||||
? `1px solid ${zone.mainHex}30`
|
||||
: '1px solid rgba(255,59,92,0.25)',
|
||||
color: subscription.is_active ? zone.mainHex : '#FF3B5C',
|
||||
: subscription.is_limited
|
||||
? '1px solid rgba(255,184,0,0.25)'
|
||||
: '1px solid rgba(255,59,92,0.25)',
|
||||
color: subscription.is_active
|
||||
? zone.mainHex
|
||||
: subscription.is_limited
|
||||
? '#FFB800'
|
||||
: '#FF3B5C',
|
||||
}}
|
||||
>
|
||||
{subscription.is_active
|
||||
? subscription.is_trial
|
||||
? t('subscription.trialStatus')
|
||||
: t('subscription.active')
|
||||
: subscription.status === 'disabled'
|
||||
? t('subscription.pause.suspended')
|
||||
: t('subscription.expired')}
|
||||
: subscription.is_limited
|
||||
? t('subscription.trafficLimited')
|
||||
: subscription.status === 'disabled'
|
||||
? t('subscription.pause.suspended')
|
||||
: t('subscription.expired')}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* ─── Traffic Limited Banner ─── */}
|
||||
{subscription.is_limited && (
|
||||
<div
|
||||
className="mb-6 rounded-[14px] p-4"
|
||||
style={{
|
||||
background:
|
||||
'linear-gradient(135deg, rgba(255,184,0,0.08), rgba(255,184,0,0.03))',
|
||||
border: '1px solid rgba(255,184,0,0.2)',
|
||||
}}
|
||||
>
|
||||
<div className="flex items-start gap-3">
|
||||
<div
|
||||
className="flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-[10px]"
|
||||
style={{ background: 'rgba(255,184,0,0.12)' }}
|
||||
>
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="#FFB800"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" />
|
||||
<line x1="12" y1="9" x2="12" y2="13" />
|
||||
<line x1="12" y1="17" x2="12.01" y2="17" />
|
||||
</svg>
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<p className="text-sm font-semibold" style={{ color: '#FFB800' }}>
|
||||
{t('subscription.trafficLimitedTitle')}
|
||||
</p>
|
||||
<p className="mt-1 text-xs text-dark-400">
|
||||
{t('subscription.trafficLimitedDescription')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ─── Trial Info Banner ─── */}
|
||||
{subscription.is_trial && subscription.is_active && (
|
||||
<div
|
||||
@@ -988,11 +1041,13 @@ export default function Subscription() {
|
||||
{t('subscription.pause.title')}
|
||||
</h2>
|
||||
<div className="mt-1 text-[12px] text-dark-50/35">
|
||||
{subscription.status === 'disabled'
|
||||
? t('subscription.pause.suspended')
|
||||
: subscription.is_daily_paused
|
||||
? t('subscription.pause.paused')
|
||||
: t('subscription.pause.active')}
|
||||
{subscription.is_limited
|
||||
? t('subscription.trafficLimited')
|
||||
: subscription.status === 'disabled'
|
||||
? t('subscription.pause.suspended')
|
||||
: subscription.is_daily_paused
|
||||
? t('subscription.pause.paused')
|
||||
: t('subscription.pause.active')}
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
@@ -1140,7 +1195,7 @@ export default function Subscription() {
|
||||
|
||||
{/* Additional Options (Buy Devices) */}
|
||||
{subscription &&
|
||||
subscription.is_active &&
|
||||
(subscription.is_active || subscription.is_limited) &&
|
||||
!subscription.is_trial &&
|
||||
subscription.device_limit !== 0 && (
|
||||
<div
|
||||
|
||||
Reference in New Issue
Block a user