| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- import { useMemo } from 'react'
- import { useTranslation } from 'react-i18next'
- import { useAuthStore } from '@/stores/auth-store'
- import { useStatus } from '@/hooks/use-status'
- export type TopNavLink = {
- title: string
- href: string
- disabled?: boolean
- external?: boolean
- }
- // Default navigation configuration
- const DEFAULT_HEADER_NAV_MODULES = {
- home: true,
- console: true,
- pricing: { enabled: true, requireAuth: false },
- rankings: { enabled: true, requireAuth: false },
- docs: true,
- about: true,
- }
- function parseAccessModule(
- raw: unknown,
- fallback: { enabled: boolean; requireAuth: boolean }
- ) {
- if (
- typeof raw === 'boolean' ||
- typeof raw === 'string' ||
- typeof raw === 'number'
- ) {
- return {
- enabled: raw === true || raw === 'true' || raw === '1' || raw === 1,
- requireAuth: fallback.requireAuth,
- }
- }
- if (raw && typeof raw === 'object') {
- const record = raw as Record<string, unknown>
- return {
- enabled:
- typeof record.enabled === 'boolean' ? record.enabled : fallback.enabled,
- requireAuth:
- typeof record.requireAuth === 'boolean'
- ? record.requireAuth
- : fallback.requireAuth,
- }
- }
- return { ...fallback }
- }
- function parseHeaderNavModules(
- raw: unknown
- ): typeof DEFAULT_HEADER_NAV_MODULES {
- if (!raw || String(raw).trim() === '') {
- return DEFAULT_HEADER_NAV_MODULES
- }
- try {
- const parsed = JSON.parse(String(raw)) as Record<string, unknown>
- return {
- ...DEFAULT_HEADER_NAV_MODULES,
- ...parsed,
- pricing: parseAccessModule(
- parsed.pricing,
- DEFAULT_HEADER_NAV_MODULES.pricing
- ),
- rankings: parseAccessModule(
- parsed.rankings,
- DEFAULT_HEADER_NAV_MODULES.rankings
- ),
- }
- } catch {
- return DEFAULT_HEADER_NAV_MODULES
- }
- }
- /**
- * Generate top navigation links based on HeaderNavModules configuration from backend /api/status
- * Backend format example (stringified JSON):
- * {
- * home: true,
- * console: true,
- * pricing: { enabled: true, requireAuth: false },
- * rankings: { enabled: true, requireAuth: false },
- * docs: true,
- * about: true
- * }
- */
- export function useTopNavLinks(): TopNavLink[] {
- const { t } = useTranslation()
- const { status } = useStatus()
- const { auth } = useAuthStore()
- // Parse HeaderNavModules
- const modules = useMemo(() => {
- return parseHeaderNavModules(status?.HeaderNavModules)
- }, [status?.HeaderNavModules])
- // Documentation link (may be external)
- const docsLink: string | undefined = status?.docs_link as string | undefined
- const isAuthed = !!auth?.user
- const links: TopNavLink[] = []
- // Home
- if (modules?.home !== false) {
- links.push({ title: t('Home'), href: '/' })
- }
- // Console -> /dashboard (new console path)
- if (modules?.console !== false) {
- links.push({ title: t('Console'), href: '/dashboard' })
- }
- // Pricing
- const pricing = modules?.pricing
- if (pricing && typeof pricing === 'object' && pricing.enabled) {
- const disabled = pricing.requireAuth && !isAuthed
- links.push({ title: t('Model Square'), href: '/pricing', disabled })
- }
- // Rankings
- const rankings = modules?.rankings
- if (rankings && typeof rankings === 'object' && rankings.enabled) {
- const disabled = rankings.requireAuth && !isAuthed
- links.push({ title: t('Rankings'), href: '/rankings', disabled })
- }
- // Docs (supports external links)
- if (modules?.docs !== false) {
- if (docsLink) {
- links.push({ title: t('Docs'), href: docsLink, external: true })
- } else {
- links.push({ title: t('Docs'), href: '/docs' })
- }
- }
- // About
- if (modules?.about !== false) {
- links.push({ title: t('About'), href: '/about' })
- }
- return links
- }
|