Add files via upload

This commit is contained in:
Egor
2026-01-18 06:22:42 +03:00
committed by GitHub
parent 8be393bf63
commit 4e1182449b
3 changed files with 40 additions and 7 deletions

View File

@@ -301,18 +301,20 @@ export default function Subscription() {
// Auto-scroll to switch tariff modal when it appears // Auto-scroll to switch tariff modal when it appears
useEffect(() => { useEffect(() => {
if (switchTariffId && switchModalRef.current) { if (switchTariffId && switchModalRef.current) {
setTimeout(() => { const timer = setTimeout(() => {
switchModalRef.current?.scrollIntoView({ behavior: 'smooth', block: 'center' }) switchModalRef.current?.scrollIntoView({ behavior: 'smooth', block: 'center' })
}, 100) }, 100)
return () => clearTimeout(timer)
} }
}, [switchTariffId]) }, [switchTariffId])
// Auto-scroll to tariff purchase form when it appears // Auto-scroll to tariff purchase form when it appears
useEffect(() => { useEffect(() => {
if (showTariffPurchase && tariffPurchaseRef.current) { if (showTariffPurchase && tariffPurchaseRef.current) {
setTimeout(() => { const timer = setTimeout(() => {
tariffPurchaseRef.current?.scrollIntoView({ behavior: 'smooth', block: 'center' }) tariffPurchaseRef.current?.scrollIntoView({ behavior: 'smooth', block: 'center' })
}, 100) }, 100)
return () => clearTimeout(timer)
} }
}, [showTariffPurchase]) }, [showTariffPurchase])
@@ -320,11 +322,12 @@ export default function Subscription() {
useEffect(() => { useEffect(() => {
const state = location.state as { scrollToExtend?: boolean } | null const state = location.state as { scrollToExtend?: boolean } | null
if (state?.scrollToExtend && tariffsCardRef.current) { if (state?.scrollToExtend && tariffsCardRef.current) {
setTimeout(() => { const timer = setTimeout(() => {
tariffsCardRef.current?.scrollIntoView({ behavior: 'smooth', block: 'center' }) tariffsCardRef.current?.scrollIntoView({ behavior: 'smooth', block: 'center' })
}, 300) }, 300)
// Clear the state to prevent re-scrolling on subsequent renders // Clear the state to prevent re-scrolling on subsequent renders
window.history.replaceState({}, document.title) window.history.replaceState({}, document.title)
return () => clearTimeout(timer)
} }
}, [location.state]) }, [location.state])

View File

@@ -32,19 +32,27 @@ export default function TelegramCallback() {
return return
} }
// Parse and validate numeric fields
const parsedId = parseInt(id, 10)
const parsedAuthDate = parseInt(authDate, 10)
if (Number.isNaN(parsedId) || Number.isNaN(parsedAuthDate)) {
setError(t('auth.telegramRequired'))
return
}
try { try {
await loginWithTelegramWidget({ await loginWithTelegramWidget({
id: parseInt(id, 10), id: parsedId,
first_name: firstName, first_name: firstName,
last_name: lastName || undefined, last_name: lastName || undefined,
username: username || undefined, username: username || undefined,
photo_url: photoUrl || undefined, photo_url: photoUrl || undefined,
auth_date: parseInt(authDate, 10), auth_date: parsedAuthDate,
hash: hash, hash: hash,
}) })
navigate('/') navigate('/')
} catch (err: unknown) { } catch (err: unknown) {
console.error('Telegram auth error:', err)
const error = err as { response?: { data?: { detail?: string } } } const error = err as { response?: { data?: { detail?: string } } }
setError(error.response?.data?.detail || t('common.error')) setError(error.response?.data?.detail || t('common.error'))
} }

View File

@@ -25,6 +25,9 @@ const getSafeRedirectUrl = (url: string | null): string => {
return url return url
} }
const MAX_RETRY_ATTEMPTS = 3
const RETRY_COUNT_KEY = 'telegram_redirect_retry_count'
export default function TelegramRedirect() { export default function TelegramRedirect() {
const { t } = useTranslation() const { t } = useTranslation()
const navigate = useNavigate() const navigate = useNavigate()
@@ -32,6 +35,10 @@ export default function TelegramRedirect() {
const { loginWithTelegram, isAuthenticated, isLoading: authLoading } = useAuthStore() const { loginWithTelegram, isAuthenticated, isLoading: authLoading } = useAuthStore()
const [status, setStatus] = useState<'loading' | 'success' | 'error' | 'not-telegram'>('loading') const [status, setStatus] = useState<'loading' | 'success' | 'error' | 'not-telegram'>('loading')
const [errorMessage, setErrorMessage] = useState('') const [errorMessage, setErrorMessage] = useState('')
const [retryCount, setRetryCount] = useState(() => {
const stored = sessionStorage.getItem(RETRY_COUNT_KEY)
return stored ? parseInt(stored, 10) : 0
})
// Get branding for nice display // Get branding for nice display
const { data: branding } = useQuery({ const { data: branding } = useQuery({
@@ -96,13 +103,28 @@ export default function TelegramRedirect() {
setTimeout(initTelegram, 300) setTimeout(initTelegram, 300)
}, [loginWithTelegram, navigate, isAuthenticated, authLoading, redirectTo, t]) }, [loginWithTelegram, navigate, isAuthenticated, authLoading, redirectTo, t])
// Handle retry // Handle retry with limit to prevent infinite loops
const handleRetry = () => { const handleRetry = () => {
if (retryCount >= MAX_RETRY_ATTEMPTS) {
setErrorMessage('Превышено количество попыток. Попробуйте позже.')
sessionStorage.removeItem(RETRY_COUNT_KEY)
return
}
const newCount = retryCount + 1
setRetryCount(newCount)
sessionStorage.setItem(RETRY_COUNT_KEY, String(newCount))
setStatus('loading') setStatus('loading')
setErrorMessage('') setErrorMessage('')
window.location.reload() window.location.reload()
} }
// Clear retry count on successful auth
useEffect(() => {
if (status === 'success') {
sessionStorage.removeItem(RETRY_COUNT_KEY)
}
}, [status])
return ( return (
<div className="min-h-screen flex items-center justify-center p-4"> <div className="min-h-screen flex items-center justify-center p-4">
{/* Background */} {/* Background */}