Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 44 additions & 14 deletions dashboard/src/pages/login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import { Input } from '@/components/ui/input'
import { LoaderButton } from '@/components/ui/loader-button'
import { PasswordInput } from '@/components/ui/password-input'
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs'
import { useAdminMiniAppToken, useAdminToken, useCreateOwner, useDeleteOwner, useResetOwnerPassword, useUpgradeOwner } from '@/service/api'
import { getCurrentAdmin, useAdminMiniAppToken, useAdminToken, useCreateOwner, useDeleteOwner, useResetOwnerPassword, useUpgradeOwner } from '@/service/api'
import { $fetch } from '@/service/http'
import { removeAuthToken, setAuthToken } from '@/utils/authStorage'
import { getAuthToken, removeAuthToken, setAuthToken } from '@/utils/authStorage'
import { queryClient } from '@/utils/query-client'
import { zodResolver } from '@hookform/resolvers/zod'
import { retrieveRawInitData } from '@telegram-apps/sdk'
Expand Down Expand Up @@ -129,18 +129,6 @@ export const Login: FC = () => {
resolver: zodResolver(schema),
})

useEffect(() => {
// Cancel all ongoing queries first to stop any in-flight requests
queryClient.cancelQueries()
// Remove the auth token
removeAuthToken()
// Clear all React Query cache to ensure fresh state after logout
queryClient.clear()
if (location.pathname !== '/login') {
navigate('/login', { replace: true })
}
}, [location.pathname, navigate])

let isTelegram = false
let initDataRaw = ''
try {
Expand All @@ -151,6 +139,48 @@ export const Login: FC = () => {
initDataRaw = ''
}

useEffect(() => {
if (location.pathname !== '/login') {
navigate('/login', { replace: true })
}
}, [location.pathname, navigate])

useEffect(() => {
// The Telegram MiniApp flow below owns its own auth exchange - let it run
// undisturbed rather than racing it over the stored token.
if (isTelegram) return

const token = getAuthToken()
// No token: nothing to verify, show the login form
if (!token) return

const controller = new AbortController()

// A token exists - check whether it's still valid before deciding
// whether to redirect to the dashboard or drop the stale session
getCurrentAdmin(controller.signal)
.then(() => {
navigate('/', { replace: true })
})
.catch((error: any) => {
if (error?.name === 'AbortError') return
// Another flow (e.g. a manual login) already replaced the token - don't clobber it
if (getAuthToken() !== token) return
// Only drop the session on a confirmed auth failure; transient/network
// errors shouldn't log out an otherwise-valid session
if (error?.status !== 401 && error?.status !== 403) return

// Cancel all ongoing queries first to stop any in-flight requests
queryClient.cancelQueries()
// Remove the auth token
removeAuthToken()
// Clear all React Query cache to ensure fresh state after logout
queryClient.clear()
})

return () => controller.abort()
}, [navigate, isTelegram])

const {
mutate: login,
isPending: loading,
Expand Down