mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 09:33:46 +00:00
fix: preserve subscription context in navigation and cache keys
SubscriptionCardActive: passes ?sub= to /connection navigation. Connection: QR state includes subscriptionId for back-navigation. ConnectionQR: preserves subscription context on back button. Dashboard + Subscription: localStorage traffic cache keyed per-subscription to prevent cooldown bleed between different subscriptions.
This commit is contained in:
@@ -214,7 +214,7 @@ export default function SubscriptionCardActive({
|
|||||||
haptic.notification('error');
|
haptic.notification('error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
navigate('/connection');
|
navigate(`/connection?sub=${subscription.id}`);
|
||||||
}}
|
}}
|
||||||
className={`mb-2.5 flex w-full items-center gap-3.5 rounded-[14px] p-3.5 text-left transition-shadow duration-300${isAtDeviceLimit ? 'cursor-not-allowed opacity-50' : ''}`}
|
className={`mb-2.5 flex w-full items-center gap-3.5 rounded-[14px] p-3.5 text-left transition-shadow duration-300${isAtDeviceLimit ? 'cursor-not-allowed opacity-50' : ''}`}
|
||||||
data-onboarding="connect-devices"
|
data-onboarding="connect-devices"
|
||||||
|
|||||||
@@ -43,9 +43,10 @@ export default function Connection() {
|
|||||||
state: {
|
state: {
|
||||||
url: appConfig?.subscriptionUrl,
|
url: appConfig?.subscriptionUrl,
|
||||||
hideLink: appConfig?.hideLink ?? false,
|
hideLink: appConfig?.hideLink ?? false,
|
||||||
|
subscriptionId: subId,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}, [navigate, appConfig?.subscriptionUrl, appConfig?.hideLink, isTelegramWebApp]);
|
}, [navigate, appConfig?.subscriptionUrl, appConfig?.hideLink, isTelegramWebApp, subId]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleKeyDown = (e: KeyboardEvent) => {
|
const handleKeyDown = (e: KeyboardEvent) => {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { AdminBackButton } from '@/components/admin';
|
|||||||
interface ConnectionQRState {
|
interface ConnectionQRState {
|
||||||
url: string;
|
url: string;
|
||||||
hideLink: boolean;
|
hideLink: boolean;
|
||||||
|
subscriptionId?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isValidState(state: unknown): state is ConnectionQRState {
|
function isValidState(state: unknown): state is ConnectionQRState {
|
||||||
@@ -24,12 +25,14 @@ export default function ConnectionQR() {
|
|||||||
|
|
||||||
const state = location.state as unknown;
|
const state = location.state as unknown;
|
||||||
const validState = isValidState(state) ? state : null;
|
const validState = isValidState(state) ? state : null;
|
||||||
|
const subId = validState?.subscriptionId;
|
||||||
|
const connectionPath = subId ? `/connection?sub=${subId}` : '/connection';
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!validState) {
|
if (!validState) {
|
||||||
navigate('/connection', { replace: true });
|
navigate(connectionPath, { replace: true });
|
||||||
}
|
}
|
||||||
}, [validState, navigate]);
|
}, [validState, navigate, connectionPath]);
|
||||||
|
|
||||||
if (!validState) {
|
if (!validState) {
|
||||||
return null;
|
return null;
|
||||||
@@ -38,7 +41,7 @@ export default function ConnectionQR() {
|
|||||||
return (
|
return (
|
||||||
<div className="animate-fade-in">
|
<div className="animate-fade-in">
|
||||||
<div className="mb-6 flex items-center gap-3">
|
<div className="mb-6 flex items-center gap-3">
|
||||||
<AdminBackButton to="/connection" replace />
|
<AdminBackButton to={connectionPath} replace />
|
||||||
<h1 className="text-2xl font-bold text-dark-100">{t('subscription.connection.qrTitle')}</h1>
|
<h1 className="text-2xl font-bold text-dark-100">{t('subscription.connection.qrTitle')}</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -141,7 +141,10 @@ export default function Dashboard() {
|
|||||||
traffic_used_percent: data.traffic_used_percent,
|
traffic_used_percent: data.traffic_used_percent,
|
||||||
is_unlimited: data.is_unlimited,
|
is_unlimited: data.is_unlimited,
|
||||||
});
|
});
|
||||||
localStorage.setItem('traffic_refresh_ts', Date.now().toString());
|
localStorage.setItem(
|
||||||
|
`traffic_refresh_ts_${subscription?.id ?? 'default'}`,
|
||||||
|
Date.now().toString(),
|
||||||
|
);
|
||||||
if (data.rate_limited && data.retry_after_seconds) {
|
if (data.rate_limited && data.retry_after_seconds) {
|
||||||
setTrafficRefreshCooldown(data.retry_after_seconds);
|
setTrafficRefreshCooldown(data.retry_after_seconds);
|
||||||
} else {
|
} else {
|
||||||
@@ -176,7 +179,7 @@ export default function Dashboard() {
|
|||||||
if (hasAutoRefreshed.current) return;
|
if (hasAutoRefreshed.current) return;
|
||||||
hasAutoRefreshed.current = true;
|
hasAutoRefreshed.current = true;
|
||||||
|
|
||||||
const lastRefresh = localStorage.getItem('traffic_refresh_ts');
|
const lastRefresh = localStorage.getItem(`traffic_refresh_ts_${subscription?.id ?? 'default'}`);
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const cacheMs = API.TRAFFIC_CACHE_MS;
|
const cacheMs = API.TRAFFIC_CACHE_MS;
|
||||||
|
|
||||||
|
|||||||
@@ -391,7 +391,10 @@ export default function Subscription() {
|
|||||||
traffic_used_percent: data.traffic_used_percent,
|
traffic_used_percent: data.traffic_used_percent,
|
||||||
is_unlimited: data.is_unlimited,
|
is_unlimited: data.is_unlimited,
|
||||||
});
|
});
|
||||||
localStorage.setItem('traffic_refresh_ts', Date.now().toString());
|
localStorage.setItem(
|
||||||
|
`traffic_refresh_ts_${subscriptionId ?? 'default'}`,
|
||||||
|
Date.now().toString(),
|
||||||
|
);
|
||||||
if (data.rate_limited && data.retry_after_seconds) {
|
if (data.rate_limited && data.retry_after_seconds) {
|
||||||
setTrafficRefreshCooldown(data.retry_after_seconds);
|
setTrafficRefreshCooldown(data.retry_after_seconds);
|
||||||
} else {
|
} else {
|
||||||
@@ -427,7 +430,7 @@ export default function Subscription() {
|
|||||||
if (hasAutoRefreshed.current) return;
|
if (hasAutoRefreshed.current) return;
|
||||||
hasAutoRefreshed.current = true;
|
hasAutoRefreshed.current = true;
|
||||||
|
|
||||||
const lastRefresh = localStorage.getItem('traffic_refresh_ts');
|
const lastRefresh = localStorage.getItem(`traffic_refresh_ts_${subscriptionId ?? 'default'}`);
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const cacheMs = 30 * 1000;
|
const cacheMs = 30 * 1000;
|
||||||
|
|
||||||
@@ -441,7 +444,7 @@ export default function Subscription() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
refreshTrafficMutation.mutate();
|
refreshTrafficMutation.mutate();
|
||||||
}, [subscription, refreshTrafficMutation]);
|
}, [subscription, refreshTrafficMutation, subscriptionId]);
|
||||||
|
|
||||||
const copyUrl = () => {
|
const copyUrl = () => {
|
||||||
if (subscription?.subscription_url) {
|
if (subscription?.subscription_url) {
|
||||||
|
|||||||
Reference in New Issue
Block a user