Загрузка данных
import { useCallback, useEffect, useState } from 'react';
import { useDispatch } from 'react-redux';
import { communicator } from '@core/comm';
import { useAppSelect } from '@hooks/useAppSelector';
import { CORPACTIONS_OPEN_EXESTED_WIDGET_EVENT, HIGHLIGHT_WIDGET_EVENT } from '@modules/widgets/shared';
import { addContentPropsToWidget, unbindWidgets } from '@store/slices/widgets';
import { getState } from '@store/store';
import { useWidgetsBind } from '@utils/hooks/useWidgetsBind';
import { DEFAULT_SYMBOL } from '../const';
import { useChartPublicContext } from './useChartPublicContext';
import type { Contract } from '@modules/contracts';
import type { Dispatch, SetStateAction } from 'react';
import type { Widget } from 'types/Widgets';
import type { WidgetProperties } from '../properties/types';
import type { ChartContainerProps } from '../types';
interface UseChartComponentFacadeReturn {
dropDownOpen: boolean;
setDropdownOpen: Dispatch<SetStateAction<boolean>>;
currentInstrument: string;
isWidgetHeaderContextMenuOpen: boolean;
setIsWidgetHeaderContextMenuOpen: Dispatch<SetStateAction<boolean>>;
onDropInstruments: (val: string, withUpdate?: boolean) => void;
addInstrumentFromModal: (instruments: Pick<Contract, 'issKey'>[]) => void;
isOver: boolean;
}
type SaveContentPropsOptions = Partial<WidgetProperties['chartState']> & {
withUpdate?: boolean;
cleanIndicativeData?: boolean;
};
export default function useChartComponentFacade(
props: ChartContainerProps,
): UseChartComponentFacadeReturn {
const { widgetId } = props;
const dispatch = useDispatch();
const [isOver, setIsOver] = useState(false);
const [dropDownOpen, setDropdownOpen] = useState(false);
const [isWidgetHeaderContextMenuOpen, setIsWidgetHeaderContextMenuOpen] = useState(false);
const widgetProperties = useAppSelect(
(state) => state.widgets.widgets.find(({ id }) => id === widgetId)?.widgetContentProps,
) as WidgetProperties | undefined;
const [currentInstrument, setCurrentInstrument] = useState(
widgetProperties?.chartState?.savedInstrument ?? DEFAULT_SYMBOL,
);
const { triggerRelatedWidgetsToUpdate, getMasterInstrumentFromPublicContext } = useWidgetsBind({
widgetId,
});
const saveContentProps = useCallback(
(val: SaveContentPropsOptions): void => {
const { withUpdate, cleanIndicativeData, ...chartStateVal } = val;
// Используем прямой доступ к стору, чтобы получить актуальные свойства виджета
const oldProps = (getState().widgets.widgets.find(({ id }) => id === widgetId) as Widget | undefined)
?.widgetContentProps;
if (!oldProps) {
return;
}
dispatch(
addContentPropsToWidget({
id: widgetId,
withoutSend: !withUpdate,
widgetContentProps: {
chartState: {
...oldProps.chartState,
...chartStateVal,
},
// при смене инструмента очищаем индикативные данные, переданные из виджета Индикативные котировки
indicativeData: cleanIndicativeData ? undefined : oldProps.indicativeData,
},
}),
);
},
[dispatch, widgetId],
);
useEffect(() => {
triggerRelatedWidgetsToUpdate(currentInstrument);
}, [currentInstrument, triggerRelatedWidgetsToUpdate]);
const onInstrumentChange = useCallback(
(newVal: string, withUpdate?: boolean, unbind = true): void => {
setCurrentInstrument(newVal);
if (unbind) {
dispatch(unbindWidgets({ widgetId }));
}
// при смене инструмента очищаем индикативные данные виджета график
// т.к. логика для графика индикатива построена на наличии в widgetContentProps данных indicativeData
saveContentProps({
savedInstrument: newVal,
withUpdate,
cleanIndicativeData: true,
});
setIsWidgetHeaderContextMenuOpen(false);
},
[dispatch, saveContentProps, widgetId],
);
const addInstrumentFromModal = useCallback(
(instruments: Pick<Contract, 'issKey'>[]) => {
const issKey = instruments[0]?.issKey;
if (!issKey) {
return;
}
onInstrumentChange(issKey);
},
[onInstrumentChange],
);
const onInstrumentChangeFromBind = useCallback(
(instrumentId: string) => {
onInstrumentChange(instrumentId, true, false);
},
[onInstrumentChange],
);
const onDropInstruments = useCallback(
(val: string, withUpdate?: boolean): void => {
onInstrumentChange(val, withUpdate);
},
[onInstrumentChange],
);
useChartPublicContext({
setCurrInstrument: onInstrumentChangeFromBind,
widgetId,
getMasterInstrumentFromPublicContext,
});
useEffect(() => {
const unsubscribe = communicator.listen(
{
messageType: CORPACTIONS_OPEN_EXESTED_WIDGET_EVENT,
},
(message) => {
const issKey = (message as Record<number, string>)[widgetId];
if (issKey) {
addInstrumentFromModal([{ issKey }]);
}
},
);
const unsubscribeHighlighter = communicator.listen(
{
messageType: HIGHLIGHT_WIDGET_EVENT,
},
(message) => {
const typedMessage = message as Record<number, boolean>;
if (Object.keys(typedMessage).includes(String(widgetId))) {
setIsOver(typedMessage[widgetId]);
}
},
);
return () => {
unsubscribe();
unsubscribeHighlighter();
};
}, [addInstrumentFromModal, widgetId]);
return {
dropDownOpen,
setDropdownOpen,
currentInstrument,
isWidgetHeaderContextMenuOpen,
setIsWidgetHeaderContextMenuOpen,
onDropInstruments,
addInstrumentFromModal,
isOver,
};
}