diff --git a/src/components/dashboard/SubscriptionCardExpired.tsx b/src/components/dashboard/SubscriptionCardExpired.tsx
index e9817b9..1a18c5a 100644
--- a/src/components/dashboard/SubscriptionCardExpired.tsx
+++ b/src/components/dashboard/SubscriptionCardExpired.tsx
@@ -77,7 +77,9 @@ export default function SubscriptionCardExpired({ subscription }: SubscriptionCa
- {t('dashboard.expired.title')}
+ {subscription.is_trial
+ ? t('dashboard.expired.trialTitle')
+ : t('dashboard.expired.title')}
{subscription.is_trial
@@ -117,27 +119,21 @@ export default function SubscriptionCardExpired({ subscription }: SubscriptionCa
- {/* Expired info grid */}
+ {/* Expired date */}
- {[
- { label: t('dashboard.expired.traffic'), value: '0 GB' },
- { label: t('dashboard.expired.devices'), value: '0' },
- { label: t('dashboard.expired.expiredDate'), value: formattedDate },
- ].map((item, i) => (
-
-
- {item.label}
-
-
{item.value}
-
- ))}
+
+ {t('dashboard.expired.expiredDate')}
+
+
+ {formattedDate}
+
{/* Action buttons */}
diff --git a/src/pages/Subscription.tsx b/src/pages/Subscription.tsx
index a416c3f..a8de6b8 100644
--- a/src/pages/Subscription.tsx
+++ b/src/pages/Subscription.tsx
@@ -187,6 +187,25 @@ export default function Subscription() {
// Extract subscription from response (null if no subscription)
const subscription = subscriptionResponse?.subscription ?? null;
+ // Live countdown timer
+ const [countdown, setCountdown] = useState({ days: 0, hours: 0, minutes: 0, seconds: 0 });
+ useEffect(() => {
+ if (!subscription?.end_date) return;
+ const endTime = new Date(subscription.end_date).getTime();
+ const tick = () => {
+ const diff = Math.max(0, endTime - Date.now());
+ setCountdown({
+ days: Math.floor(diff / 86_400_000),
+ hours: Math.floor((diff % 86_400_000) / 3_600_000),
+ minutes: Math.floor((diff % 3_600_000) / 60_000),
+ seconds: Math.floor((diff % 60_000) / 1_000),
+ });
+ };
+ tick();
+ const id = setInterval(tick, 1000);
+ return () => clearInterval(id);
+ }, [subscription?.end_date]);
+
const { data: purchaseOptions, isLoading: optionsLoading } = useQuery({
queryKey: ['purchase-options'],
queryFn: subscriptionApi.getPurchaseOptions,
@@ -679,7 +698,6 @@ export default function Subscription() {
const zone = getTrafficZone(usedPercent);
const connectedDevices = devicesData?.total ?? 0;
const formattedDate = new Date(subscription.end_date).toLocaleDateString();
- const daysLeft = subscription.days_left;
return (
{isUnlimited ? t('dashboard.unlimited') : t(zone.labelKey)}
- {subscription.is_trial && (
-
- {t('subscription.trialStatus')}
-
- )}
{/* Plan name */}
@@ -770,11 +775,11 @@ export default function Subscription() {
color: subscription.is_active ? zone.mainHex : '#FF3B5C',
}}
>
- {subscription.is_trial
- ? t('subscription.trialStatus')
- : subscription.is_active
- ? t('subscription.active')
- : t('subscription.expired')}
+ {subscription.is_active
+ ? subscription.is_trial
+ ? t('subscription.trialStatus')
+ : t('subscription.active')
+ : t('subscription.expired')}
@@ -992,57 +997,114 @@ export default function Subscription() {
{/* ─── Stats Row ─── */}
- {/* Days left */}
-
-
+ {/* Countdown timer */}
+ {(() => {
+ const isUrgent = countdown.days <= 3;
+ const isExpired = !subscription.is_active;
+ return (
-
+
+
+ {t('dashboard.remaining')}
+
+ {isExpired ? (
+
+ {t('subscription.expired')}
+
+ ) : (
+
+ {countdown.days > 0 && (
+ <>
+
+ {countdown.days}
+
+
+ {t('subscription.daysShort')}
+
+ >
+ )}
+
+ {String(countdown.hours).padStart(2, '0')}
+
+
+ :
+
+
+ {String(countdown.minutes).padStart(2, '0')}
+
+
+ :
+
+
+ {String(countdown.seconds).padStart(2, '0')}
+
+
+ )}
+
+ {t('subscription.expiresAt')}: {formattedDate}
+
- {t('dashboard.remaining')}
-
-
-
- {daysLeft > 0
- ? daysLeft
- : subscription.hours_left > 0
- ? `${subscription.hours_left}h`
- : `${subscription.minutes_left}m`}
-
-
- {daysLeft > 0 ? t('subscription.daysShort') : ''}
-
-
-
+ );
+ })()}
{/* Devices */}
-
+
-
- {/* Expires */}
-
-
- {t('subscription.expiresAt')}
-
-
- {formattedDate}
-
-
-
- {/* Traffic */}
-
-
- {t('subscription.traffic')}
-
-
- {isUnlimited ? '∞' : `${usedPercent.toFixed(0)}%`}
-
-
{/* ─── Locations ─── */}