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


import { AxiosResponse } from 'axios';

import axios, { axiosInstanceTus } from '@api/axios';

import type { ResponseStatusCodes } from '@api/models/responseStatusCodes';
import type { PartialWithRequired } from 'types/utilityTypes';
import type { Widget, WidgetPackedProps } from 'types/Widgets';

interface TerminalResponse {
  headers: Record<string, never>;
  statusCode: 'OK';
  statusCodeValue: ResponseStatusCodes.OK;
}

export const widgetPropertiesController = {
  create(data: WidgetPackedProps[]): Promise<AxiosResponse<TerminalResponse>> {
    return axiosInstanceTus.post('/api/v1/widgetproperty/save-list', data);
  },
  read(data: Widget['id'][]): Promise<AxiosResponse<WidgetPackedProps[]>> {
    return axiosInstanceTus.post('/api/v1/widgetproperty/get-list', data);
  },
  update(data: PartialWithRequired<WidgetPackedProps, 'widgetId'>): Promise<AxiosResponse<WidgetPackedProps[]>> {
    return axiosInstanceTus.put('/api/v1/widgetproperty', data);
  },
  delete(data: Pick<Widget, 'id'>): Promise<AxiosResponse<undefined>> {
    return axiosInstanceTus.delete('/api/v1/widgetproperty', { data });
  },
};

















import axios, { axiosInstanceTus } from '../axios';

import type { AxiosResponse } from 'axios';
import type { Widget } from 'types/Widgets';
import type { Workspace } from 'types/Workspace';

type WidgetCreateArgs = Pick<Widget, 'name' | 'workspaceId'>;
type WidgetCreateResponse = WidgetCreateArgs & Pick<Widget, 'id'>;

export const widgetsController = {
  async create(data: WidgetCreateArgs[]): Promise<AxiosResponse<WidgetCreateResponse[]>> {
    return axiosInstanceTus.post('/api/v1/widgets/save-list', data);
  },
  async update(data: WidgetCreateResponse): Promise<AxiosResponse<undefined>> {
    return axiosInstanceTus.put('/api/v1/widgets', data);
  },
  async read(ids: Workspace['id'][]): Promise<AxiosResponse<Record<number, WidgetCreateResponse[]>>> {
    return axiosInstanceTus.post('/api/v1/widgets/get-list', ids);
  },
  async delete(item: Widget): Promise<AxiosResponse<undefined>> {
    return axiosInstanceTus.delete(`/api/v1/widgets/${(item as Widget).id}`);
  },
};


















import dayjs, { type Dayjs } from 'dayjs';

import { feedbackController } from '@api/controllers/feedbackController';

import { commonDateFormat } from '@configs/standartDateFormat';
import { getStore } from '@store/store';
import { AboutInstrumentTradingResultType } from 'types/AboutInstrument';

import { Candle } from 'types/Candles';
import { ResponseChatByPlacementId } from 'types/ResponseChatIdByPlacement';

import axios, {
  axiosCurves,
  axiosIndicative,
  axiosInstanceFormalization,
  axiosInstanceNews,
  axiosInstanceNTBAnalytics,
  axiosInstanceNTBTrading,
  axiosInstanceNTPro,
  axiosInstanceSPFI,
  axiosInstanceTD,
  axiosInstanceTMD,
  axiosInstanceTus,
  uninterceptedAxiosInstance,
} from './axios';

import { abbrevationsController } from './controllers/abbrevationsController';
import { candlesController } from './controllers/candles';
import { frontExceptionController } from './controllers/frontExceptionController';
import { newsSettingsController } from './controllers/newsController';
import { noTradeChatController } from './controllers/noTradeChatController';
import { tradeChatController } from './controllers/tradeChatController';
import { widgetPropertiesController } from './controllers/widgetProperties';
import { widgetsController } from './controllers/widgets';
import { workspaceController } from './controllers/workspace';

import type { ResponseSearchSmartType } from '@components/InputSearchCommand/type/type';
import type { Contract } from '@modules/contracts';
import type { BoardType, Counterparty } from '@widgets/AboutInstrument/types';
import type { QuotesNTProTypeServer } from '@widgets/QuotesNTPro/type';

import type { AxiosRequestConfig, AxiosResponse } from 'axios';
import type { IChatFolder, IChatMessages, ICreateChatFolder, IUpdateChatFolder } from 'types/Chats';
import type {
  CurveValue,
  IndicativeCurveFilters,
  IndicativeCurveType,
  IssCurveFilters,
  IssCurveGroup,
  IssCurveType,
  ZeroCouponCurveLiveRequestParams,
  ZeroCouponCurveLiveResponse,
} from 'types/Curves';
import type { CustomerDataType } from 'types/Customers';
import type { Firm } from 'types/Firm';
import type { FixingData } from 'types/FixingData';
import type { Instrument } from 'types/Instruments';
import type { INewsFeed, INewsItem } from 'types/News';
// import type { NSDCostType } from 'types/NSDCost';
import type { Payment } from 'types/Payment';
import type { QuotesType } from 'types/Quotes';
import type { GetBarsParams } from 'types/Requests/BarsTypes';
import type { SittingCB } from 'types/SittingCB';
import type { User, UserSettings } from 'types/User';

const api = {
  getBars({ currencyPair, interval, date, count }: GetBarsParams) {
    return axiosInstanceTD.get<Candle[]>(
      `/api/v1/candles/list/offset?secId=${currencyPair}&date=${date}&interval=${interval}&count=${count}`,
    );
  },
  getQuotes() {
    return axios.post('api/v1/blotters/quotes', {
      timestamp: -1,
      keys: [
        'AIX:MAIN:BAST',
        'AIX:MAIN:Bond',
        'AIX:MAIN:0000000000000',
        'AIX:MAIN:aix123',
        'AIX:AOTC:EQOTCa',
        'AIX:MAIN:TickEQ1',
        'AIX:MAIN:COVID19',
        'AIX:MAIN:HSBK',
        'AIX:MAIN:Forte_AIX',
        'AIX:MAIN:Tatn_AIX',
        'AIX:MAIN:170920201635',
        'INT:IUSA:123987',
        'INT:IUSA:HSBK_priv_IUSA',
        'INT:IUSA:AAPL',
        'INT:IUSA:aaa8888811122',
        'INT:IUSA:aaa1',
        'INT:IUSA:171107122020',
        'KSE:TQBR:RAHT',
        'KSE:EQBR:HSBKp',
        'KSE:TQBR:KZTK',
        'KSE:TQBR:KZAP',
        'KSE:TQBR:HSBK',
        'KSE:TQBR:hydro10',
        'INT:ILSE:KAZ',
        'INT:IOTC:EQOTCI',
        'INT:ILSE:tick_test1201',
        'INT:IOTC:test_IOTS1201',
        'INT:ILSE:tick_009',
        'INT:ILSE:13360812',
        'INT:ILSE:Forte_LSE',
        'INT:IUSA:Test666',
      ],
    });
  },
  getMarketDepth(key: Contract['key']) {
    return axiosInstanceTMD.post('/api/v1/blotters/marketdepths', {
      key,
      timestamp: -1,
    });
  },
  workspaceController,
  widgetsController,
  widgetPropertiesController,
  frontExceptionController,
  candlesController,
  newsSettingsController,
  getChatCustomers(market?: string, spfiTradingPermission?: boolean) {
    const { isIframeView } = getStore().getState().coreSlice;
    if (isIframeView) {
      return axiosInstanceFormalization.get<CustomerDataType[]>('/api/v1/data/cache/customers')
    }
    return axios.get<CustomerDataType[]>('/api/v1/data/cache/customers', { params: { market, spfiTradingPermission } });
  },
  /* Bookbuilder: получение customers для конкретного id размещения */
  getChatCustomersByPlacement(placementId: string) {
    return axiosInstanceFormalization.get<CustomerDataType[]>(`/api/v1/data/cache/customers/placement/${placementId}`);
  },
  getCounterparties() {
    return axios.get<CustomerDataType[]>('/api/v1/data/customers');
  },
  getCounterpartiesById(id: number) {
    return axios.get<Counterparty>(`/api/v1/data/customers/${id}`, {
      full: true,
    } as AxiosRequestConfig<{ full: boolean }>);
  },
  getInstrumentById(id: number): Promise<AxiosResponse<Instrument>> {
    return axios.get(`/api/v1/data/instruments/${id}`);
  },
  getInstrumentList(): Promise<AxiosResponse<Instrument[]>> {
    return axios.get('/api/v1/data/instruments?');
  },
  tradeChatController,
  noTradeChatController,
  getNewsList(dateRange: string[]) {
    return axiosInstanceTD.get(`news/getList?from=${dateRange[0]}&till=${dateRange[1]}`);
  },
  getQuotesList() {
    return axiosInstanceTD.get('quotes/');
  },
  getBoardByInstrumentId(id: number, floorCode: string) {
    return axios.get<BoardType[]>(`/api/v1/data/boards?floorCode=${floorCode}&instrumentId=${id}`);
  },
  getDealsList(isTradeChat = false) {
    return axios.get(`/api/v1/blotters/deals${isTradeChat ? '?isTradeChat=true' : ''}`);
  },
  hideTrade(talkId: number) {
    return axios.put(`api/v1/blotters/deals/hide/${talkId}`);
  },
  getTermsDict() {
    return axiosInstanceTD.get<{ dictionary: Record<string, string> }>('/api/v1/contracts/dictionary/term');
  },
  getBoardsDict() {
    return axiosInstanceTD.get<{ dictionary: Record<string, string> }>('/api/v1/contracts/dictionary/board');
  },
  getInstrGroupDict() {
    return axiosInstanceTD.get<{ dictionary: Record<string, string> }>('/api/v1/contracts/dictionary/instrGroupType');
  },
  getIssContracts() {
    return axiosInstanceTD.get<Contract[]>('/api/v1/contracts');
  },
  getIndicativeContracts() {
    return axiosIndicative.get<Contract[]>('/api/v1/contracts');
  },
  getNtProContracts() {
    return axiosInstanceNTPro.get<Contract[]>('/api/v1/contracts');
  },
  getSapfirContracts() {
    return axiosInstanceSPFI.get<Contract[]>('/api/v1/contracts');
  },
  getNtbAnalyticsContracts() {
    return axiosInstanceNTBAnalytics.get<Contract[]>('/api/v1/contracts');
  },
  getNtbContracts() {
    return axiosInstanceNTBTrading.get<Contract[]>('/api/v1/contracts');
  },
  getFixingsList(): Promise<AxiosResponse<FixingData[]>> {
    return axiosInstanceTD.get('/api/fixings/');
  },
  getFixingById(key: string): Promise<AxiosResponse<FixingData[]>> {
    return axiosInstanceTD.get(`/api/fixings?code=${key}`);
  },
  getQuotesByKeys(keys: string[], signal?: AbortSignal) {
    return axiosInstanceTD.put<QuotesType[]>('/api/v1/quotes', keys, { signal });
  },
  getQuotesByIndicativeKeys(keys: string[], signal?: AbortSignal) {
    return axiosIndicative.put<QuotesType[]>('/api/v1/quotes', keys, { signal });
  },
  getQuotesListWithParams({ skip, limit }: { skip: number; limit: number }) {
    return axiosInstanceTD.get<QuotesType[]>('/api/v1/quotes/list', {
      params: {
        skip,
        limit,
      },
    });
  },
  getTurnoversByDate(date: Date) {
    const year = date.getFullYear();
    const month = date.getMonth() + 1 < 10 ? `0${date.getMonth() + 1}` : date.getMonth() + 1;
    const day = date.getDate() < 10 ? `0${date.getDate()}` : date.getDate();

    const newDate = `${year}-${month}-${day}`;

    return axiosInstanceTD.get(`/api/v1/turnovers?date=${newDate}`);
  },

  /** Кривые */
  getCurveGroups() {
    return axiosCurves.get<IssCurveGroup[]>('/api/v1/data/curves/groups');
  },
  getCurves() {
    return axiosCurves.get<IssCurveType[]>('/api/v1/data/curves');
  },
  getCurvesFilter: (params: { groupCurveId?: number; id?: number; currencyCode?: string } = {}) =>
    axiosCurves.get<IssCurveFilters>('/api/v1/data/curvesfilter', { params }),
  getCurvePoints(groupId: number, curveId: number, date: Date | string) {
    const newDate = date instanceof Date ? dayjs(date).format(commonDateFormat.backendDateFormat) : date;
    return axiosCurves.get<CurveValue[]>(`/api/v1/data/curvepoints/${groupId}/${curveId}/${newDate}`);
  },

  getZeroCouponCurveLive: (params?: ZeroCouponCurveLiveRequestParams) =>
    axiosInstanceTD.post<ZeroCouponCurveLiveResponse>('/api/v1/kbd/live', params),

  /** Кривые индикативные котировок */
  getIndicativeCurves: () => axiosIndicative.get<IndicativeCurveType[]>('/api/v1/data/curves'),
  getIndicativeCurveFilter: (params: { groupCurveId?: number; curveId?: string; currencyCode?: string } = {}) =>
    axiosIndicative.get<IndicativeCurveFilters>('/api/v1/data/curvesfilter', { params }),
  getIndicativeCurvePoints(key: string, date: Dayjs) {
    const formattedDate = date.format(commonDateFormat.backendDateFormat);
    return axiosIndicative.get<CurveValue[]>(`/api/v1/data/curvepoints/${key}/${formattedDate}`);
  },

  getQuoteByIssKey(key: string) {
    const issKeyParts = key.split(':');
    return axiosInstanceTD.get<QuotesType>(
      `/api/v1/quotes?secId=${issKeyParts[2]}&boardId=${issKeyParts[1]}&tradingSystem=${issKeyParts[0]}`,
    );
  },
  getPaymentsByIsin(isin: string) {
    return axiosInstanceTD.get<Payment[]>(`/api/v1/payments?isin=${isin}`);
  },
  getTradingResults(security: string, date: string | Dayjs, board: string) {
    return axiosInstanceTD.get<AboutInstrumentTradingResultType[]>(
      `api/trading-result?mode=instrument&security=${security}&till=${date}&from=${date}&board=${board}`,
    );
  },
  getQuotesNTPro() {
    return axiosInstanceNTPro.get<QuotesNTProTypeServer[]>('/quotes');
  },
  getIndexesBySecId(key: string) {
    const issKeyParts = key.split(':');
    return axios.get(`/api/v1/data/indexes/${issKeyParts[2]}`);
  },
  getUserPermissions(): Promise<AxiosResponse<string[]>> {
    return axios.get('/api/v1/permission/user');
  },
  /** Получение основной информации по пользователю */
  getCurrentUserInfo(): Promise<AxiosResponse<User>> {
    return axios.get('api/v1/users/current');
  },
  updateMenuLocked(id: number, locked: boolean): Promise<AxiosResponse<User>> {
    return axios.patch('api/v1/users/settings', {
      user_id: id,
      is_menu_locked: locked,
    });
  },
  updateUser(user: User): Promise<AxiosResponse<User>> {
    return axios.put('api/v1/users', user);
  },
  getCurrentUserSettings(id: number) {
    return axios.get<UserSettings>(`/api/v1/notification-users/${id}`);
  },
  updateCurrentUserSettings(settigs: UserSettings) {
    return axios.put('api/v1/notification-users', settigs);
  },
  getSearchSmart(search: string, signal: AbortSignal) {
    return axiosInstanceTus.get<ResponseSearchSmartType>(`/api/v1/search-smart?search=${encodeURIComponent(search)}`, {
      signal,
    });
  },
  healthcheckTd(): Promise<AxiosResponse<{ status: string }>> {
    return axiosInstanceTD.get('/actuator/health-td');
  },
  healthcheckTb(): Promise<AxiosResponse<{ status: string }>> {
    return axios.get('/actuator/health-tb');
  },
  healthcheckSPFI(): Promise<AxiosResponse<{ status: string }>> {
    return axiosInstanceSPFI.get('/actuator/health-spfi');
  },
  healthcheckForm(): Promise<AxiosResponse<{ status: string }>> {
    return axiosInstanceFormalization.get('/actuator/health-form');
  },
  connectionCheckRequest(): Promise<AxiosResponse<{ status: string }>> {
    return uninterceptedAxiosInstance.get('https://iss.moex.com/iss/sitenews/');
  },
  getFirms(): Promise<AxiosResponse<Firm[]>> {
    return axios.get('/api/v1/data/cache/firms');
  },
  abbrevationsController,
  feedbackController,
  // Отключено в рамках TRADERADAR-12666 Отключение источника НРД
  // getNSDCost() {
  //   return axiosInstanceTD.get<NSDCostType[]>('/api/v1/data/nsdCost');
  // },
  getChatFolders(): Promise<AxiosResponse<IChatFolder[]>> {
    return axiosInstanceFormalization.get('/api/v1/folders');
  },
  createChatFolder(folderData: ICreateChatFolder): Promise<AxiosResponse<IChatFolder>> {
    return axiosInstanceFormalization.post('/api/v1/folders', folderData);
  },
  deleteChatFolder(folderId: number): Promise<AxiosResponse> {
    return axiosInstanceFormalization.delete(`/api/v1/folders/${folderId}`);
  },
  updateChatFolder(folderData: IUpdateChatFolder): Promise<AxiosResponse<IChatFolder>> {
    return axiosInstanceFormalization.patch(`/api/v1/folders/${folderData.folderId}`, folderData);
  },
  updateFolderPosition(folderPosition: Record<string, number>): void {
    axiosInstanceFormalization.post('/api/v1/folders/positions', folderPosition);
  },
  sendChatMessages(data: IChatMessages): Promise<AxiosResponse> {
    return axiosInstanceFormalization.post('/api/v1/chat-messages', data);
  },
  getNewsItemById(newsId: string): Promise<AxiosResponse<INewsItem>> {
    return axiosInstanceNews.get(`/api/v1/news/${newsId}`);
  },
  findNewsByText(text?: string): Promise<AxiosResponse<INewsItem[]>> {
    const requestUrl = `/api/v1/news/search${text ? `?search=${encodeURIComponent(text)}` : ''}`;
    return axiosInstanceNews.get(requestUrl);
  },
  getCombinedNews(searchParams?: string): Promise<AxiosResponse<INewsItem[]>> {
    const requestUrl = searchParams ? `/api/v1/news/search?${searchParams}` : '/api/v1/news/search';
    return axiosInstanceNews.get(requestUrl);
  },
  getNewsFeeds(): Promise<AxiosResponse<INewsFeed[]>> {
    return axiosInstanceNews.get('/api/v1/newsfeeds');
  },

  getContractsIssInfo(): Promise<AxiosResponse<{ key: string }>> {
    return axiosInstanceTD.get('/api/v1/contracts/info');
  },
  getSittingCB() {
    return axiosInstanceTD.get<SittingCB>('/api/v1/data/sittingCB');
  },
  getChatIdByPlacement(placementId: string) {
    return axiosInstanceFormalization.get<ResponseChatByPlacementId>(`/api/v1/chats/placement/${placementId}`);
  },
};

export default api;

export type Api = typeof api;

















import { AxiosResponse } from 'axios';
import chunk from 'lodash/chunk';
import { all, call, put, select } from 'typed-redux-saga';

import api from '@api/index';
import { TRADE_PERMISSION, WIDGET_PROPS_REQUEST_CHUNK_SIZE } from '@configs/appConfig';
import { permissionsSelector } from '@store/selectors/user';
import { metricsAction } from '@store/slices/core';
import { createValuesToPublicContext, PublicContextItem } from '@store/slices/publicContext';
import { addWidget } from '@store/slices/widgets';
import { addWorkspace } from '@store/slices/workspaces';
import { isRemovedWidget } from '@utils/isRemovedWidget';
import { robustRequest } from '@utils/robustRequest';
import { unpackWidgetProps } from '@utils/widgetPropsProceeders';
import { convertPercentToPx } from '@utils/widgetSizesNPositionProceeders';
import { MetricsAction } from 'types/MetricsActions';
import { WidgetPackedProps } from 'types/Widgets';
import { Workspace } from 'types/Workspace';

function* processProperties(workspacesIdList: number[]) {
  const publicPropertiesResponse = yield* call(async () =>
    robustRequest(() => api.widgetsController.read(workspacesIdList)),
  );
  const publicProperties = publicPropertiesResponse.data;

  const result: PublicContextItem[] = [];
  Object.values(publicProperties).forEach((elem) => {
    elem.forEach((item) => {
      const arrPublicProps = Object.values((item as PublicContextItem).publicProperties || []).map((obj) =>
        JSON.parse(obj as unknown as string),
      );
      result.push({
        ...(item as unknown as PublicContextItem),
        publicProperties: arrPublicProps,
      } as PublicContextItem);
    });
  });
  yield put(createValuesToPublicContext(result));
  return Object.values(publicProperties)
    .flat(1)
    .map(({ id }) => id);
}

function processWidgetsData(response: AxiosResponse<WidgetPackedProps[]>[]) {
  return response
    .flatMap((chunkResult) => chunkResult.data)
    .filter(({ properties }) => !isRemovedWidget(properties))
    .map((i) => {
      const unpackedWidget = unpackWidgetProps(convertPercentToPx(i));
      if (!unpackedWidget.isExpand && unpackedWidget.beforeExpandParams) {
        unpackedWidget.beforeExpandParams = null;
      }
      if (!unpackedWidget.widgetContentProps) {
        unpackedWidget.widgetContentProps = {};
      }

      return unpackedWidget;
    })
}

export function* fullWorkspacesUploadSaga() {
  const permissions = yield* select(permissionsSelector);
  const isCanTrade = permissions.includes(TRADE_PERMISSION);

  const workspacesShortInfoResponse = yield* call(() => robustRequest(api.workspaceController.read));
  yield put(metricsAction(MetricsAction.LOADING_SCREEN_TIME_WORKSPACES));
  const workspaces: Workspace[] = workspacesShortInfoResponse.data;
  workspaces
    .sort((a, b) => a.position - b.position)
    .map(({ saved, pinned, code, ...workspace }) => ({
      saved: saved || false,
      pinned: pinned || false,
      code: code ?? null,
      ...workspace,
    }));
  if (workspaces.length > 0) {
    let workspacesForStore = workspaces;
    if (!isCanTrade) {
      workspacesForStore = workspaces.filter(({ name }) => name !== 'Переговоры');
    }
    yield put(addWorkspace(workspacesForStore));
  } else {
    return;
  }

  const workspacesIdList = workspaces.map(({ id }) => id);
  const widgetIdList = yield* processProperties(workspacesIdList);

  // Получение подробной информации по виджетам
  // Предположительно можно выполнить параллельно с запросом на проперти
  const widgetIdChunks = chunk(widgetIdList, WIDGET_PROPS_REQUEST_CHUNK_SIZE);
  const widgetsData = yield* all(
    widgetIdChunks.map((v) => call(() => robustRequest(() => api.widgetPropertiesController.read(v)))),
  );
  const widgets = processWidgetsData(widgetsData);
  if (widgets.length > 0) {
    yield put(addWidget(widgets));
  }
}
















/* eslint-disable no-await-in-loop */

import { AxiosError } from 'axios';

const ATTEMPTS = 10;

/** Функция вызывающая передаваемую функцию несколько раз в случае исключения
 * @param f - Функция которую необходимо выполнить
 * @param axiosValidErrorCodes - массив значений кодов ошибок после которых не нужно кидать ошибку
*/
export async function robustRequest<T>(f: () => Promise<T>, axiosValidErrorCodes?: number[]): Promise<T> {
  let cnt = ATTEMPTS - 1;
  let timeoutMs = 100;
  while (cnt > 0) {
    try {
      const result = await f();
      return result;
    } catch (error) {
      if (axiosValidErrorCodes) {
        const axiosError = error as AxiosError;
        if (axiosError.status && axiosValidErrorCodes.includes(axiosError.status)) {
          // eslint-disable-next-line @typescript-eslint/no-explicit-any -- прокидываем ошибку axios
          throw new Error(error as any)
        }
      }
      console.log(error)
    }
    // eslint-disable-next-line no-loop-func -- gg
    await new Promise((r) => {
      setTimeout(() => r(1), timeoutMs);
    });
    timeoutMs *= 2;
    cnt -= 1;
  }
  throw new Error();
}


















import { all, call, fork, join, put, select } from 'typed-redux-saga';

import { instrumentListsController } from '@api/controllers/instrumentLists';
import { profileController } from '@api/controllers/profileController';
import api from '@api/index';
import { getIsSpfiTrader } from '@api/utils/getIsSpfiTrader';
import { wsEndpointStompClient } from '@api/websokets/classes/WSEndpointStompClient';
import { systemNotificationController } from '@api/websokets/systemNotification/systemNotificationController';

import { initStorageData } from '@store/sagas/initStorageData';
// import { addNSDCost } from '@store/slices/cashedData';
import { desktopCriticalDataReceived, metricsAction } from '@store/slices/core';
import { setFirms } from '@store/slices/firms';
import { setIntrumentLists } from '@store/slices/instrumentLists';
import { setAvatarUrl, setPersonalData, setPrivacySettings } from '@store/slices/user';
import { getStore, RootState } from '@store/store';

import { MetricsAction } from 'types/MetricsActions';

import { contractsRequestSaga } from '../basic/contracts';
import { newsInitSaga } from '../basic/news';
import { chatsCacheSyncSaga } from '../chats/initChat';
import { customersAndChatsSaga } from '../customersAndChats';
import { initChatAvatars } from '../initAvatars';
import { initSurveys } from '../surveys/init';
import { requestAndPut } from '../utils';
import { fullWorkspacesUploadSaga } from '../workspaces';

/** В этот момент пропадает экран загрузки и пользователь видит терминал */
export function* backgroundDesktopReceiverSaga() {
  yield* fork(async () => {
    try {
      const res = await profileController.getAvatar();
      getStore().dispatch(setAvatarUrl(res.data ? URL.createObjectURL(res.data) : null));
    } catch {
      getStore().dispatch(setAvatarUrl(null));
    }
  });

  yield* fork(newsInitSaga);
  yield* fork(initChatAvatars);

  yield* fork(initStorageData);
  yield* fork(chatsCacheSyncSaga);
  yield* fork(initSurveys);
}

export function* criticalDesktopReceiverSaga() {
  if (yield* select((state: RootState) => state.coreSlice.desktopCriticalDataReceived)) {
    return;
  }

  // Активируем соединение для большого количества виджетов
  wsEndpointStompClient.activate();

  // Активация контроллера системных уведомлений
  const isSpfiTrader = yield* select(getIsSpfiTrader);
  systemNotificationController.activate(isSpfiTrader);

  const customersAndChatsFork = yield* fork(customersAndChatsSaga);
  const workspacesFork = yield* fork(fullWorkspacesUploadSaga);

  // eslint-disable-next-line func-names -- в сагах нормально
  const contractsAndTradeFork = yield* fork(function* () {
    yield call(contractsRequestSaga);
  });

  // eslint-disable-next-line func-names -- в сагах нормально
  const massRequestsFork = yield* fork(function* () {
    yield all([
      // Нужно в виджете контакты, входящий звонок, список переговоров
      requestAndPut(setFirms, api.getFirms, MetricsAction.LOADING_SCREEN_TIME_CATA_CACHE_FIRMS),
      // Отключено в рамках TRADERADAR-12666 Отключение источника НРД
      // requestAndPut(addNSDCost, api.getNSDCost, MetricsAction.LOADING_SCREEN_TIME_DATA_NSDCOST),
      requestAndPut(
        setIntrumentLists,
        instrumentListsController.getInstrumentLists,
        MetricsAction.LOADING_SCREEN_TIME_LISTINSTRUMENTS,
      ),
      // TODO: убрать отсюда когда появится статус загрузки
      requestAndPut(
        setPersonalData,
        profileController.getPersonalData,
        MetricsAction.LOADING_SCREEN_TIME_USERS_PERSONAL_DATA,
      ),
      // TODO: убрать отсюда когда появится статус загрузки
      requestAndPut(
        setPrivacySettings,
        profileController.getPrivacySettings,
        MetricsAction.LOADING_SCREEN_TIME_USERS_PRIVACY_SETTINGS,
      ),
    ]);
  });

  yield* join([customersAndChatsFork, workspacesFork, contractsAndTradeFork, massRequestsFork]);

  yield put(metricsAction(MetricsAction.LOADING_SCREEN_TIME_END));
  yield put(desktopCriticalDataReceived());
  yield* call(backgroundDesktopReceiverSaga);
}

















import { all, takeEvery, takeLeading } from 'typed-redux-saga';

import { requestLastReceivedMessages } from '@store/actions/chats';
import {
  initMetrics,
  initNotifications,
  metricsAction,
  metricTimer,
  requestAppCriticalData,
  requestDesktopCriticalData,
  requestMobileCriticalData,
} from '@store/slices/core';

import { initLastMessagesSaga } from '../chats/initChat';
import { initMetricsSaga, sendMetricsSaga, sendTimerMetricAction } from '../metrics';
import { initNotificationsSaga } from '../notifications';

import { criticalDesktopReceiverSaga } from './desktop';
import { criticalMobileReceiverSaga } from './mobile';
import { criticalTerminalDataReceiverSaga } from './terminal';

export function* coreSagas() {
  yield all([
    takeLeading(initMetrics, initMetricsSaga),
    takeEvery(metricsAction, sendMetricsSaga),
    takeEvery(metricTimer, sendTimerMetricAction),
    takeLeading(requestAppCriticalData, criticalTerminalDataReceiverSaga),
    takeLeading(requestMobileCriticalData, criticalMobileReceiverSaga),
    takeLeading(requestDesktopCriticalData, criticalDesktopReceiverSaga),
    takeLeading(initNotifications, initNotificationsSaga),
    takeLeading(requestLastReceivedMessages, initLastMessagesSaga),
  ]);
}

















import { all } from 'redux-saga/effects';

import { watchCommission } from '@modules/MXT/shared/commission/model/saga';
import { watchLimitEstimation } from '@modules/MXT/shared/limitEstimation/model/saga';
import { watchPriceRange } from '@modules/MXT/shared/priceRange/model/saga';
import { mxtSagas } from '@store/sagas/mxt';

import { watchAddressDepositForm } from './addressDepositForm';
import { watchAddressDepositWithdrawalForm } from './addressDepositWithdrawalForm';
import { authSaga } from './auth';
import avatarsSagas from './avatars';
import { chatsSaga } from './chats';
import { coreSagas } from './core';
import { curvesSaga } from './curves';
import { customersSaga } from './customers';
import { watchDepositForm } from './depositForm';
import { watchDepositWithdrawalForm } from './depositWithdrawalForm';
import { notificationsSaga } from './notifications';
import { oidSaga } from './oids';
import { profileSaga } from './profile';
import { surveysSaga } from './surveys';
import { tradeJournalSaga } from './tradeJournal';

export default function* rootSaga() {
  yield all([
    coreSagas(),
    avatarsSagas(),
    profileSaga(),
    chatsSaga(),
    authSaga(),
    notificationsSaga(),
    customersSaga(),
    watchAddressDepositForm(),
    watchAddressDepositWithdrawalForm(),
    watchDepositWithdrawalForm(),
    watchDepositForm(),
    watchCommission(),
    watchLimitEstimation(),
    watchPriceRange(),
    tradeJournalSaga(),
    oidSaga(),
    curvesSaga(),
    mxtSagas(),
    surveysSaga(),
  ]);
}


















import { combineReducers, configureStore } from '@reduxjs/toolkit';

import createSagaMiddleware from 'redux-saga';

// Нужно так для мока саг в тестах
import commissionReducer from '@modules/MXT/shared/commission/model/slice';
import limitEstimationReducer from '@modules/MXT/shared/limitEstimation/model/slice';
import priceRangeReducer from '@modules/MXT/shared/priceRange/model/slice';
import rootSaga from '@store/sagas';

import { chatSliceMiddleware } from './middlewares/chatSliceMiddleware';
import addressDepositForm from './slices/addressDepositForm';
import addressDepositWithdrawalForm from './slices/addressDepositWithdrawalForm';
import alertsSlice from './slices/alerts';
import auth from './slices/auth';
import cashedData from './slices/cashedData';
import chatDataByPlacementId from './slices/chatDataByPlacementId';
import chatSlice from './slices/chatSlice';
import coreSlice from './slices/core';
import curvesSlice from './slices/curves';
import depositForm from './slices/depositForm';
import depositWithdrawalForm from './slices/depositWithdrawalForm';
import firmsSlice from './slices/firms';
import instrumentLists from './slices/instrumentLists';
import issuersSlice from './slices/issuers';
import localisation from './slices/localisation';
import modalsSlice from './slices/modals';
import mxtSlice from './slices/mxt';
import newsSettings from './slices/newsSettings';
import newsSlice from './slices/newsSlice';
import ntbLogisticSlice from './slices/ntb/logistic';
import ntbOrdersAndDealsSlice from './slices/ntb/ordersAndDeals';
import ntbPositionsSlice from './slices/ntb/positions';
import orderbookSlice from './slices/orderbook';
import ordersJournalSlice from './slices/ordersJournalSlice';
import publicContext from './slices/publicContext';
import rcauth from './slices/rcauth';
import requestStatus from './slices/requestStatus';
import screenerSlice from './slices/screener';
import searchNews from './slices/searchNews';
import sidebarConfig from './slices/sidebarConfig';
import surveys from './slices/surveys';
import tourSlice from './slices/tour';
import tradeJournalSlice from './slices/tradeJournal';
import userSlice from './slices/user';
import widgets from './slices/widgets';
import workspaces from './slices/workspaces';

const sagaMiddleware = createSagaMiddleware();

const rootReducer = combineReducers({
  coreSlice,
  publicContext,
  workspaces,
  localisation,
  widgets,
  rcauth,
  depositForm,
  addressDepositForm,
  addressDepositWithdrawalForm,
  depositWithdrawalForm,
  formCommission: commissionReducer,
  formLimitEstimation: limitEstimationReducer,
  formPriceRange: priceRangeReducer,
  cashedData,
  curvesSlice,
  userSlice,
  alertsSlice,
  chatSlice,
  firmsSlice,
  sidebarConfig,
  newsSlice,
  newsSettings,
  searchNews,
  instrumentLists,
  modalsSlice,
  issuersSlice,
  tourSlice,
  ntbPositionsSlice,
  ntbOrdersAndDealsSlice,
  ntbLogisticSlice,
  auth,
  screenerSlice,
  ordersJournalSlice,
  tradeJournalSlice,
  requestStatus,
  orderbookSlice,
  mxtSlice,
  chatDataByPlacementId,
  surveys,
});

export const setupStore = (preloadedState?: Partial<RootState>) => {
  const store = configureStore({
    reducer: rootReducer,
    preloadedState,
    middleware: (getDefaultMiddleware) => [
      ...getDefaultMiddleware({
        serializableCheck: false,
      }),
      sagaMiddleware,
      chatSliceMiddleware,
    ],
  });
  sagaMiddleware.run(rootSaga);
  return store;
};

export type RootState = ReturnType<typeof rootReducer>;
export type AppStore = ReturnType<typeof setupStore>;