98 lines
2.8 KiB
TypeScript
98 lines
2.8 KiB
TypeScript
import { useState, useMemo, useCallback, useEffect } from 'react'
|
|
import { CategoryTemplate } from '@repo/sdk'
|
|
import { useTranslation } from 'react-i18next'
|
|
|
|
export interface Category {
|
|
id: string
|
|
name: string
|
|
nameEn?: string
|
|
templates?: CategoryTemplate[]
|
|
}
|
|
|
|
export interface UseTabNavigationOptions {
|
|
categories: Category[]
|
|
initialCategoryId?: string | null
|
|
}
|
|
|
|
export interface UseTabNavigationReturn {
|
|
activeIndex: number
|
|
selectedCategoryId: string | null
|
|
currentCategory: Category | undefined
|
|
tabs: string[]
|
|
selectTab: (index: number) => void
|
|
selectCategoryById: (categoryId: string) => void
|
|
}
|
|
|
|
export function useTabNavigation(options: UseTabNavigationOptions): UseTabNavigationReturn {
|
|
const { categories, initialCategoryId } = options
|
|
const { i18n } = useTranslation()
|
|
|
|
// State for active tab index
|
|
const [activeIndex, setActiveIndex] = useState<number>(() => {
|
|
if (initialCategoryId) {
|
|
const index = categories.findIndex(c => c.id === initialCategoryId)
|
|
return index >= 0 ? index : 0
|
|
}
|
|
return 0
|
|
})
|
|
|
|
// State for selected category ID
|
|
const [selectedCategoryId, setSelectedCategoryId] = useState<string | null>(() => {
|
|
if (initialCategoryId) {
|
|
const exists = categories.some(c => c.id === initialCategoryId)
|
|
if (exists) {
|
|
return initialCategoryId
|
|
}
|
|
}
|
|
return categories.length > 0 ? categories[0].id : null
|
|
})
|
|
|
|
// Auto-select first category when categories change and no selection
|
|
useEffect(() => {
|
|
if (categories.length > 0 && !selectedCategoryId) {
|
|
setSelectedCategoryId(categories[0].id)
|
|
setActiveIndex(0)
|
|
}
|
|
}, [categories, selectedCategoryId])
|
|
|
|
// Generate tabs array from category names with i18n support
|
|
const tabs = useMemo(() => {
|
|
const isEnglish = i18n.language === 'en-US'
|
|
return categories.map(category => {
|
|
// Use English name if available and language is English, otherwise use Chinese name
|
|
return isEnglish && category.nameEn ? category.nameEn : category.name
|
|
})
|
|
}, [categories, i18n.language])
|
|
|
|
// Get current category based on selectedCategoryId
|
|
const currentCategory = useMemo(() => {
|
|
return categories.find(c => c.id === selectedCategoryId)
|
|
}, [categories, selectedCategoryId])
|
|
|
|
// Select tab by index
|
|
const selectTab = useCallback((index: number) => {
|
|
if (index >= 0 && index < categories.length) {
|
|
setActiveIndex(index)
|
|
setSelectedCategoryId(categories[index].id)
|
|
}
|
|
}, [categories])
|
|
|
|
// Select category by ID
|
|
const selectCategoryById = useCallback((categoryId: string) => {
|
|
const index = categories.findIndex(c => c.id === categoryId)
|
|
if (index >= 0) {
|
|
setActiveIndex(index)
|
|
setSelectedCategoryId(categoryId)
|
|
}
|
|
}, [categories])
|
|
|
|
return {
|
|
activeIndex,
|
|
selectedCategoryId,
|
|
currentCategory,
|
|
tabs,
|
|
selectTab,
|
|
selectCategoryById,
|
|
}
|
|
}
|