/
kreyndelHam
/
Konstructorium
Обзор
Документация
Войти
/
kreyndelHam
/
Konstructorium
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
1
CI/CD
Аналитика
Безопасность
dev
frontend/src/hooks/useWebAnalytics.js
158 строк
5 KB
MihahamYT
Fixed errors
17 май 2026, 19:21
17 май 2026, 19:21
e1d82b6
Код
Авторство
О чём код?
import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { adminAnalyticsService } from '../services/api' /** * Map bundle payload to the shape expected by WebAnalyticsSection per tab. * * @param {object|null} bundle * @param {string} activeTab * @returns {object|null} */ const selectTabDataFromBundle = (bundle, activeTab) => { if (!bundle) { return null } switch (activeTab) { case 'traffic': return { overview: bundle.traffic?.overview || {}, timeseries: bundle.traffic?.timeseries || [], } case 'pages': return bundle.pages || null case 'sources': return bundle.sources || null case 'technology': return bundle.technology || null case 'errors': return bundle.errors || null case 'api': return bundle.api || null case 'realtime': return bundle.realtime || null default: return null } } /** * Stable serialization for optional query params (avoids effect churn on `{}` identity). * * @param {Record<string, unknown>} extraParams * @returns {string} */ const serializeExtraParams = (extraParams) => JSON.stringify(extraParams || {}) /** * Load web analytics for admin dashboard: one HTTP request per filter set, tabs read from cache. * * @param {string} activeTab * @param {string} dateFrom * @param {string} dateTo * @param {string} interval * @param {import('../hooks/useTranslation').TranslateFn} t * @param {Record<string, unknown>} [extraParams] * @returns {{loading: boolean, isRefreshing: boolean, data: object|null, reload: () => void, loadError: string|null}} */ export function useWebAnalytics(activeTab, dateFrom, dateTo, interval, t, extraParams = {}) { const [loading, setLoading] = useState(false) const [isRefreshing, setIsRefreshing] = useState(false) const [bundle, setBundle] = useState(null) const [loadError, setLoadError] = useState(null) const cacheRef = useRef({}) const bundleRef = useRef(null) const extraParamsKey = serializeExtraParams(extraParams) bundleRef.current = bundle const filterKey = `${dateFrom}:${dateTo}:${interval}:${extraParamsKey}` const buildParams = useCallback( () => ({ from: dateFrom, to: dateTo, interval, ...JSON.parse(extraParamsKey || '{}'), }), [dateFrom, dateTo, extraParamsKey, interval], ) const loadBundle = useCallback(async ({ force = false } = {}) => { if (!force && cacheRef.current[filterKey]) { setBundle(cacheRef.current[filterKey]) return } const hasExistingData = Boolean(cacheRef.current[filterKey] || bundleRef.current) if (!hasExistingData) { setLoading(true) } else { setIsRefreshing(true) } try { const response = await adminAnalyticsService.getWebBundle(buildParams()) cacheRef.current[filterKey] = response.data setBundle(response.data) setLoadError(null) } catch (error) { const unavailable = error?.response?.status === 503 || error?.response?.data?.error?.includes?.('not available') setLoadError(unavailable ? 'unavailable' : 'failed') if (!error?.__userErrorHandled) { console.error('Failed to load web analytics bundle:', error) } } finally { setLoading(false) setIsRefreshing(false) } }, [buildParams, filterKey]) useEffect(() => { Object.keys(cacheRef.current).forEach((key) => { if (key !== filterKey) { delete cacheRef.current[key] } }) loadBundle() }, [filterKey, loadBundle]) useEffect(() => { if (activeTab !== 'realtime') { return undefined } const timer = setInterval(async () => { try { const response = await adminAnalyticsService.getWebRealtime(buildParams()) setBundle((previous) => { if (!previous) { return previous } const next = { ...previous, realtime: response.data } cacheRef.current[filterKey] = next return next }) } catch (error) { if (!error?.__userErrorHandled) { console.error('Failed to refresh web analytics realtime:', error) } } }, 30000) return () => clearInterval(timer) }, [activeTab, buildParams, filterKey]) const reload = useCallback(() => { delete cacheRef.current[filterKey] loadBundle({ force: true }) }, [filterKey, loadBundle]) const data = useMemo( () => selectTabDataFromBundle(bundle, activeTab), [activeTab, bundle], ) return { loading, isRefreshing, data, loadError, reload } } export const WEB_ANALYTICS_TABS = ['traffic', 'pages', 'sources', 'technology', 'errors', 'api', 'realtime']