Implement activation requirement for protected routes
- Added a new `useRequireActivated` hook to enforce user activation before accessing certain routes, redirecting unauthenticated users to the login page and inactive users to the dashboard. - Updated the `InstructionsPage` and `NewsPage` components to utilize the new activation check, enhancing user flow and security. - Conditional rendering of navigation links in the `RootLayout` based on user activation status, improving user experience by hiding inaccessible features.
This commit is contained in:
@@ -37,3 +37,17 @@ export function useRequireAdmin() {
|
||||
|
||||
return { user, isReady: !isBootstrapping && !!user && user.role === 'admin' }
|
||||
}
|
||||
|
||||
/** Как useRequireAuth, но дополнительно требует активацию — иначе редирект на дашборд (там форма запроса активации). */
|
||||
export function useRequireActivated() {
|
||||
const { user, isBootstrapping } = useAuthStore()
|
||||
const navigate = useNavigate()
|
||||
|
||||
useEffect(() => {
|
||||
if (isBootstrapping) return
|
||||
if (!user) void navigate({ to: '/login' })
|
||||
else if (!user.isActivated) void navigate({ to: '/dashboard' })
|
||||
}, [isBootstrapping, user, navigate])
|
||||
|
||||
return { user, isReady: !isBootstrapping && !!user && user.isActivated }
|
||||
}
|
||||
|
||||
@@ -44,12 +44,16 @@ function RootLayout() {
|
||||
<Link to="/dashboard" className="text-muted-foreground hover:text-foreground">
|
||||
{t('nav.dashboard')}
|
||||
</Link>
|
||||
{user.isActivated && (
|
||||
<>
|
||||
<Link to="/instructions" className="text-muted-foreground hover:text-foreground">
|
||||
{t('nav.instructions')}
|
||||
</Link>
|
||||
<Link to="/news" className="text-muted-foreground hover:text-foreground">
|
||||
{t('nav.news')}
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
<Link to="/settings" className="text-muted-foreground hover:text-foreground">
|
||||
{t('nav.settings')}
|
||||
</Link>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { createFileRoute } from '@tanstack/react-router'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useRequireAuth } from '@/features/auth/guards'
|
||||
import { useRequireActivated } from '@/features/auth/guards'
|
||||
import { AppsCatalog } from '@/features/apps/AppsCatalog'
|
||||
|
||||
export const Route = createFileRoute('/instructions')({ component: InstructionsPage })
|
||||
|
||||
function InstructionsPage() {
|
||||
const { t } = useTranslation()
|
||||
const { isReady } = useRequireAuth()
|
||||
const { isReady } = useRequireActivated()
|
||||
|
||||
if (!isReady) return null
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { createFileRoute } from '@tanstack/react-router'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useRequireAuth } from '@/features/auth/guards'
|
||||
import { useRequireActivated } from '@/features/auth/guards'
|
||||
import { NewsFeed } from '@/features/news/NewsFeed'
|
||||
|
||||
export const Route = createFileRoute('/news')({ component: NewsPage })
|
||||
|
||||
function NewsPage() {
|
||||
const { t } = useTranslation()
|
||||
const { isReady } = useRequireAuth()
|
||||
const { isReady } = useRequireActivated()
|
||||
|
||||
if (!isReady) return null
|
||||
|
||||
|
||||
Reference in New Issue
Block a user