import { useCallback, useEffect, useMemo, useState } from "react" import { useTranslation } from "react-i18next" import { Transition } from "@/features/transitions/types/transitions" import advancedTransitionsData from "../data/advanced-transitions.json" import dynamicTransitionsData from "../data/dynamic-transitions.json" import glitchTransitionsData from "../data/glitch-transitions.json" import transitionsData from "../data/transitions.json" import { createFallbackTransition, processTransitions, validateTransitionsData } from "../utils/transition-processor" // Импортируем JSON файлы напрямую - в Tauri это работает отлично // Глобальное состояние для переходов чтобы избежать рекурсивных вызовов let globalTransitions: Transition[] = [] let globalLoading = true let globalError: string | null = null let globalInitialized = false /** * Сбрасывает глобальное состояние (для тестов) * @internal */ export function resetTransitionsState() { globalTransitions = [] globalLoading = true globalError = null globalInitialized = false } interface UseTransitionsReturn { transitions: Transition[] loading: boolean error: string | null reload: () => void isReady: boolean } /** * Инициализация переходов при первом использовании */ function initializeTransitions(t: (key: string, fallback?: string, options?: any) => string) { if (globalInitialized) return try { // Загружаем базовые переходы const baseData = transitionsData if (!validateTransitionsData(baseData)) { throw new Error(t("transitions.errors.invalidTransitionsData", "Invalid base transitions data structure")) } // Загружаем расширенные переходы const advancedData = advancedTransitionsData if (!validateTransitionsData(advancedData)) { console.warn("Invalid advanced transitions data, skipping advanced transitions") } // Загружаем динамические переходы const dynamicData = dynamicTransitionsData if (!validateTransitionsData(dynamicData)) { console.warn("Invalid dynamic transitions data, skipping dynamic transitions") } // Загружаем glitch переходы const glitchData = glitchTransitionsData if (!validateTransitionsData(glitchData)) { console.warn("Invalid glitch transitions data, skipping glitch transitions") } // Объединяем переходы из всех файлов const allTransitions = [ ...baseData.transitions, ...(advancedData && validateTransitionsData(advancedData) ? advancedData.transitions : []), ...(dynamicData && validateTransitionsData(dynamicData) ? dynamicData.transitions : []), ...(glitchData && validateTransitionsData(glitchData) ? glitchData.transitions : []), ] console.log( `Loading ${baseData.transitions.length} base + ${advancedData?.transitions?.length || 0} advanced + ${dynamicData?.transitions?.length || 0} dynamic + ${glitchData?.transitions?.length || 0} glitch transitions`, ) // Обрабатываем переходы (преобразуем в типизированные объекты) globalTransitions = processTransitions(allTransitions) globalError = null console.log( `✅ ${t("transitions.messages.transitionsLoaded", "Loaded {{count}} transitions from JSON", { count: globalTransitions.length })}`, ) } catch (err) { const errorMessage = err instanceof Error ? err.message : t("transitions.errors.unknownError", "Unknown error") globalError = t("transitions.errors.failedToLoadTransitions", "Failed to load transitions: {{error}}", { error: errorMessage, }) // Создаем fallback переходы в случае ошибки globalTransitions = [ createFallbackTransition("fade"), createFallbackTransition("zoom"), createFallbackTransition("slide"), ] console.error( `❌ ${t("transitions.errors.fallbackTransitions", "Failed to load transitions, using fallback")}:`, err, ) } finally { globalLoading = false globalInitialized = true } } /** * Хук для загрузки и управления переходами из JSON файла */ export function useTransitions(): UseTransitionsReturn { const { t } = useTranslation() const [transitions, setTransitions] = useState(globalTransitions) const [loading, setLoading] = useState(globalLoading) const [error, setError] = useState(globalError) /** * Загружает переходы из импортированного JSON файла */ const loadTransitions = useCallback(() => { // Создаем обертку для функции t, чтобы она соответствовала ожидаемой сигнатуре const translateWrapper = (key: string, fallback?: string, options?: Record) => { const result = t(key, fallback || key, options) return typeof result === "string" ? result : JSON.stringify(result) } initializeTransitions(translateWrapper) setTransitions(globalTransitions) setLoading(globalLoading) setError(globalError) }, [t]) // Загружаем переходы при монтировании компонента useEffect(() => { loadTransitions() }, [loadTransitions]) return { transitions, loading, error, reload: loadTransitions, isReady: !loading && transitions.length > 0, } } /** * Хук для получения конкретного перехода по ID */ export function useTransitionById(transitionId: string): Transition | null { const { t } = useTranslation() // Инициализируем переходы если еще не инициализированы useMemo(() => { const translateWrapper = (key: string, fallback?: string, options?: Record) => { const result = t(key, fallback || key, options) return typeof result === "string" ? result : JSON.stringify(result) } initializeTransitions(translateWrapper) }, [t]) const transition = useMemo(() => { if (globalLoading || !globalTransitions.length) { return null } return globalTransitions.find((transition: Transition) => transition.id === transitionId) || null }, [transitionId]) return transition } /** * Хук для получения переходов по категории */ export function useTransitionsByCategory(category: string): Transition[] { const { t } = useTranslation() // Инициализируем переходы если еще не инициализированы useMemo(() => { const translateWrapper = (key: string, fallback?: string, options?: Record) => { const result = t(key, fallback || key, options) return typeof result === "string" ? result : JSON.stringify(result) } initializeTransitions(translateWrapper) }, [t]) const filteredTransitions = useMemo(() => { if (globalLoading || !globalTransitions.length) { return [] } return globalTransitions.filter((transition: Transition) => transition.category === category) }, [category]) return filteredTransitions } /** * Хук для поиска переходов */ export function useTransitionsSearch(query: string, lang: "ru" | "en" = "ru"): Transition[] { const { t } = useTranslation() // Инициализируем переходы если еще не инициализированы useMemo(() => { const translateWrapper = (key: string, fallback?: string, options?: Record) => { const result = t(key, fallback || key, options) return typeof result === "string" ? result : JSON.stringify(result) } initializeTransitions(translateWrapper) }, [t]) const searchResults = useMemo(() => { if (globalLoading || !globalTransitions.length || !query.trim()) { return globalTransitions } const lowercaseQuery = query.toLowerCase() return globalTransitions.filter( (transition: Transition) => (transition.labels?.[lang] || transition.id || "").toLowerCase().includes(lowercaseQuery) || (transition.description?.[lang] || "").toLowerCase().includes(lowercaseQuery) || (transition.tags || []).some((tag: string) => tag.toLowerCase().includes(lowercaseQuery)), ) }, [query, lang]) return searchResults }