Загрузка данных


import { useRef, useEffect } from 'react';
import {
  MoexChart as ChartMoex,
  IMoexChart,
  MoexChartSnapshot,
} from '@mx-charts/charts';
import { logger } from '~/utils/logger';

import '@mx-charts/charts/dist/styles.css';
import styles from './styles.module.scss';

type TradeRadarChartProps = {
  height: number;
  chartConfig: Omit<IMoexChart, 'container'>;
  storageKey: string | undefined;
};

export const TradeRadarChart = ({
  height = 500,
  chartConfig,
  storageKey,
}: TradeRadarChartProps) => {
  const containerRef = useRef<HTMLDivElement | null>(null);
  const chartRef = useRef<ChartMoex | null>(null);
  const currentSymbol = chartConfig.snapshot?.charts?.[0]?.symbolId || '';

  useEffect(() => {
    const container = containerRef.current;

    if (!container) {
      return;
    }

    const saved = storageKey ? localStorage.getItem(storageKey) : undefined;
    let configWithSnapshot = chartConfig;

    if (saved) {
      try {
        const savedSnapshot = JSON.parse(saved) as MoexChartSnapshot;

        if (savedSnapshot.charts && savedSnapshot.charts.length > 0) {
          savedSnapshot.charts[0].symbol = currentSymbol;
          savedSnapshot.charts[0].symbolId = currentSymbol;
        }

        configWithSnapshot = {
          ...chartConfig,
          snapshot: savedSnapshot,
        };
      } catch (e) {
        logger.error('Failed to parse saved snapshot', { error: e });
      }
    }

    const { supportedTimeframes } = configWithSnapshot.chartCollectionPreset;
    const { timeframe } = configWithSnapshot.snapshot.charts[0];
    if (!supportedTimeframes.includes(timeframe)) {
      configWithSnapshot.snapshot.charts[0].timeframe = supportedTimeframes[0];
    }

    chartRef.current = new ChartMoex({
      ...configWithSnapshot,
      container,
    });

    const chart = chartRef.current;

    return () => {
      chart.destroy();
      chartRef.current = null;
    };
  }, [chartConfig, currentSymbol, storageKey]);

  useEffect(() => {
    const saveSnapshot = () => {
      const chart = chartRef.current;

      if (!chart || !storageKey) return;

      try {
        const snapshot = chartRef.current?.getSnapshot();

        if (!snapshot) {
          return;
        }

        const savedData = JSON.stringify({
          ...snapshot,
          charts: snapshot.charts.map((c) => ({
            ...c,
            symbol: currentSymbol,
            symbolId: currentSymbol,
            panes: c.panes.map((p) => ({
              ...p,
              drawings: [],
              indicators: p.indicators.map((i) => ({
                ...i,
                dataSource: undefined,
                config: undefined,
              })),
            })),
          })),
        });

        localStorage.setItem(storageKey, savedData);
      } catch (e) {
        logger.error('Failed to save advanced chart snapshot', { error: e });
      }
    };

    const handleVisibilityChange = () => {
      if (document.visibilityState === 'hidden') {
        saveSnapshot();
      }
    };

    const handleBeforeUnload = () => {
      saveSnapshot();
    };

    document.addEventListener('visibilitychange', handleVisibilityChange);
    window.addEventListener('beforeunload', handleBeforeUnload);

    return () => {
      document.removeEventListener('visibilitychange', handleVisibilityChange);
      window.removeEventListener('beforeunload', handleBeforeUnload);
    };
  }, [currentSymbol, storageKey]);

  return (
    <div className={styles.tradeRadarChart} style={{ height: `${height}px` }}>
      <div ref={containerRef} />
    </div>
  );
};

















import { IndicatorsIds } from '@mx-charts/charts';
import { useCallback, useMemo } from 'react';
import { fetchCandles } from '~/modules/FutureCard/api';
import { ChartConfigOverride } from '~/modules/TradeRadarChart';
import { FuturesAdvancedChart } from '../../../blocks/FuturesAdvancedChart';
import { useTranslation } from '../../../../translations';
import { FetchChartCandles } from '~/modules/FutureCard/types';
import { mapToChartCandles } from '../utils/mapToChartCandles';

type FuturesChartProps = {
  height?: number;
  secId: string;
  boardGroupId: number;
  market: string;
  engine: string;
  realtimeInterval?: number;
};

export const FuturesChart = (props: FuturesChartProps) => {
  const { t } = useTranslation();
  const chartConfig: ChartConfigOverride = useMemo(
    () => ({
      snapshot: {
        charts: [
          {
            panes: [
              {
                isMain: true,
                id: 0,
                indicators: [
                  {
                    indicatorType: IndicatorsIds.Volume,
                  },
                ],
                drawings: [],
              },
            ],
          },
        ],
      },
    }),
    []
  );

  const fetchChartCandles: FetchChartCandles = useCallback(async (params) => {
    const { data: candlesData, isError } = await fetchCandles(params);
    return {
      data: candlesData
        ? {
            isAuthorized: candlesData.isAuthorized,
            data: mapToChartCandles(candlesData.data),
          }
        : null,
      isError,
    };
  }, []);

  return (
    <FuturesAdvancedChart
      {...props}
      fetchChartCandles={fetchChartCandles}
      storageKey="moexFuturesChartSnapshot"
      chartConfigOverride={chartConfig}
      noDataMessage={t.quotes.chartNoDataMessage}
    />
  );
};