Preview:
/* eslint-disable no-promise-executor-return */
import dayjs from 'dayjs';
import _ from 'lodash';
import {
  useEffect, useRef, useState,
} from 'react';
import {
  useRecoilValue, useSetRecoilState,
} from 'recoil';
import { t } from 'ttag';
import {
  beatEventCountState,
  rhythmEventCountState,
  specialEventTypesState, updatedAfibAvgHrState, updatedDailyAfibHrSummariesState,
} from '.';
import { clearApolloCache } from '../../../../../Apollo/apolloClient';
import fetchHolterBeatEventsCount from '../../../../../Apollo/Functions/fetchHolterBeatEventsCount';
import fetchHolterEventIndex from '../../../../../Apollo/Functions/fetchHolterEventIndex';
import fetchHolterEvents from '../../../../../Apollo/Functions/fetchHolterEvents';
import fetchHolterEventsDailyCount from '../../../../../Apollo/Functions/fetchHolterEventsDailyCount';
import fetchHolterRhythmEventsCount from '../../../../../Apollo/Functions/fetchHolterRhythmEventsCount';
import handleCheckSavingAiProcess from '../../../../../Apollo/Functions/handleCheckSavingAiProcess';
import { EMITTER_CONSTANTS } from '../../../../../ConstantsV2';
import {
  AI_COMMAND,
  canShowCountBeatEvents, canShowDurationEvents,
  ECG_EVENT_MENU_OPTIONS, EVENT_COUNT_CONVERT, ID_BOOKMARK_TAB, KEY_CANCEL, KEY_RECOIL, STRIP_EVENT_THUMBNAIL_INFO, TYPE_RHYTHM_EVENT_ENUM,
  typesPersistEventV2,
} from '../../../../../ConstantsV2/aiConstants';
import { convertToDayJS } from '../../../../../UtilsV2/aiUtils';
import { useEmitter, useGetRecoilValue } from '../../../../../UtilsV2/customHooks';
import emitter from '../../../../../UtilsV2/eventEmitter';
import { toastrError } from '../../../../../UtilsV2/toastNotification';
import {
  activeTabState,
  beatChangesState,
  dailyCountState,
  ecgDataMapState,
  eventChangesState,
  eventFilterState,
  eventNewsState,
  eventOptionsState,
  eventOthersState,
  groupEventChangesState,
  isActiveTabState,
  isNotReadyAfterSaveState,
  isRenderViewerEcgState,
  originalDailySummariesState,
  pageIndexState,
  profileAfibAvgHrState,
  reloadEcgViewerState,
  reloadHrChartState,
  reportInfoState,
  selectedDateValueState,
  selectedStripState,
} from '../../Recoil';
import { logError } from '../../handler';
import {
  generateFilterSpecialEventType,
  isAppliedFilterEvent,
} from '../handler';
import { clearCachesBeatHourly } from '../../../../../Store/caches';
import { removeSavingData } from '../../BeatHR/helper';
import { beatOptionsState } from '../../BeatHR/recoil';

const RhythmEventsRecoilDataEffect = (props) => {
  const keyRecoil = KEY_RECOIL.TAB_2;
  const activeButton = useRecoilValue(activeTabState(keyRecoil));
  const getActiveButton = useGetRecoilValue(activeTabState(keyRecoil));
  const getSelectedStrip = useGetRecoilValue(selectedStripState(keyRecoil));
  const getPageIndex = useGetRecoilValue(pageIndexState(keyRecoil));
  const setPageIndex = useSetRecoilState(pageIndexState(keyRecoil));
  const getSelectedDateValue = useGetRecoilValue(selectedDateValueState(keyRecoil));
  const getSpecialEventTypes = useGetRecoilValue(specialEventTypesState);
  const getEventFilter = useGetRecoilValue(eventFilterState(keyRecoil));
  const setDailyCount = useSetRecoilState(dailyCountState(keyRecoil));
  const setUpdatedAfibAvgHr = useSetRecoilState(updatedAfibAvgHrState);
  const setUpdatedDailyAfibHrSummaries = useSetRecoilState(updatedDailyAfibHrSummariesState);
  const setEventChanges = useSetRecoilState(eventChangesState(keyRecoil));
  const setBeatChanges = useSetRecoilState(beatChangesState(keyRecoil));
  const setReloadEcgViewer = useSetRecoilState(reloadEcgViewerState(keyRecoil));
  const setReloadHrChart = useSetRecoilState(reloadHrChartState(keyRecoil));
  const setGroupEventChanges = useSetRecoilState(groupEventChangesState(keyRecoil));
  const isActiveTab = useRecoilValue(isActiveTabState(keyRecoil));
  const setIsNotReadyAfterSaveTab1 = useSetRecoilState(isNotReadyAfterSaveState(KEY_RECOIL.TAB_1));
  const setIsNotReadyAfterSaveTab2 = useSetRecoilState(isNotReadyAfterSaveState(KEY_RECOIL.TAB_2));
  const setIsNotReadyAfterSaveTab3 = useSetRecoilState(isNotReadyAfterSaveState(KEY_RECOIL.TAB_3));
  const getHolterRhythmEventsCount = useGetRecoilValue(rhythmEventCountState);
  const getHolterBeatEventsCount = useGetRecoilValue(beatEventCountState);
  const { studyId, profileId, timezoneOffset } = useRecoilValue(reportInfoState);
  const setEcgDataMap = useSetRecoilState(ecgDataMapState);
  const getEcgDataMap = useGetRecoilValue(ecgDataMapState);
  const setOriginalDailySummaries = useSetRecoilState(originalDailySummariesState);
  const setProfileAfibAvgHr = useSetRecoilState(profileAfibAvgHrState);
  const setEventOthers = useSetRecoilState(eventOthersState(keyRecoil));
  const setEventNews = useSetRecoilState(eventNewsState(keyRecoil));
  const setEventOptions = useSetRecoilState(eventOptionsState(keyRecoil));
  const setIsRenderViewerEcg = useSetRecoilState(isRenderViewerEcgState);
  const setHolterRhythmEventsCount = useSetRecoilState(rhythmEventCountState);
  const setHolterBeatEventsCount = useSetRecoilState(beatEventCountState);
  const setSelectedStrip = useSetRecoilState(selectedStripState(keyRecoil));
  const [doneReset, setDoneReset] = useState(false);
  const setBeatOptions = useSetRecoilState(beatOptionsState(keyRecoil));

  const commandPendingQueue = useRef([]);
  const updateDataMessageQueue = useRef([]);
  const promiseUpdateData = useRef([]);
  const promiseUpdateDataType = useRef([]);
  const isExcutedRef = useRef(false);

  const handleFetchStripEvents = async ({ page, additionalFilter = {} }) => {
    try {
      const type = getActiveButton();
      const validatePage = page <= 0 ? 0 : page;
      const filterHolterEvents = {
        studyId,
        profileId,
        types: [type],
        skip: validatePage * STRIP_EVENT_THUMBNAIL_INFO.stripDisplayLimit,
        ...additionalFilter,
      };
      const promises = [fetchHolterEvents(
        filterHolterEvents,
        STRIP_EVENT_THUMBNAIL_INFO.stripDisplayLimit,
        true,
        KEY_CANCEL.API_HOLTER_AI,
      )];
      if (!_.isEmpty(additionalFilter)) {
        const holterEventsCountFilter = {
          studyId,
          profileId,
          types: [type],
          ...additionalFilter,
        };
        promises.push(
          _.find(ECG_EVENT_MENU_OPTIONS, (x) => x.value === type).type === 'beat'
            ? fetchHolterBeatEventsCount(holterEventsCountFilter, true, KEY_CANCEL.API_HOLTER_AI)
            : fetchHolterRhythmEventsCount(holterEventsCountFilter, true, KEY_CANCEL.API_HOLTER_AI),
        );
      }
      const [{ events }, eventsCount] = await Promise.all(promises);
      if (!_.isEmpty(additionalFilter)) {
        return { events, eventsCount };
      }
      return { events, eventsCount: _.find(ECG_EVENT_MENU_OPTIONS, (x) => x.value === type).type === 'beat' ? getHolterBeatEventsCount() : getHolterRhythmEventsCount() };
    } catch (error) {
      return { events: undefined, eventsCount: 0 };
    }
  };

  const handleReloadEventHrChartV2 = async () => {
    try {
      const type = activeButton;
      const selectedDateValue = getSelectedDateValue();
      const startSearchDate = selectedDateValue;
      const stopSearchDate = selectedDateValue ? dayjs(selectedDateValue).add(1, 'days').toISOString() : null;
      const promiseArr = [
        selectedDateValue ? fetchHolterEvents({
          studyId,
          profileId,
          types: typesPersistEventV2,
          startSearchDate,
          stopSearchDate,
        }, 0, true, KEY_CANCEL.API_HOLTER_AI) : undefined,
      ];
      await Promise.allSettled(promiseArr);
      if (!_.includes(promiseUpdateDataType.current, 'setReloadHrChart')) {
        promiseUpdateDataType.current.push('setReloadHrChart');
        promiseUpdateData.current.push(() => setReloadHrChart((prev) => prev + _.round(Math.random() * 100)));
      }
    } catch (error) {
      logError('Failed to fetch reload data: ', error);
      toastrError(error.message, t`Error`);
    }
  };

  const handleReloadEventDataV2 = async (needUpdateAfibArtifact) => {
    try {
      if (isActiveTab) {
        setIsRenderViewerEcg(false);
      }
      const type = activeButton;
      const selectedDateValue = getSelectedDateValue();
      const startSearchDate = selectedDateValue;
      const stopSearchDate = selectedDateValue ? dayjs(selectedDateValue).add(1, 'days').toISOString() : null;
      const additionalFilter = generateFilterSpecialEventType(type, getSpecialEventTypes());
      const eventFilter = getEventFilter();
      if (isAppliedFilterEvent(eventFilter, type)) {
        _.assign(additionalFilter, {
          ...(eventFilter.isHideReviewed && { isReviewed: false }),
          ...(eventFilter.isCapture && { isCaptured: true }),
          ...(eventFilter.sortOrder && (canShowCountBeatEvents.includes(type) || canShowDurationEvents.includes(type)) && {
            sortBy: eventFilter.sortBy || 'countBeats',
            sortOrder: eventFilter.sortOrder,
          }),
        });
      }
      const promiseArr = [
        selectedDateValue ? fetchHolterEvents({
          studyId,
          profileId,
          types: typesPersistEventV2,
          startSearchDate,
          stopSearchDate,
        }, 0, true, KEY_CANCEL.API_HOLTER_AI) : undefined,
        fetchHolterEventsDailyCount({
          studyId,
          profileId,
          types: [type],
          ...additionalFilter,
        }, null, false),
      ];
      const selectedStrip = getSelectedStrip();
      if (selectedStrip?.idEvent) {
        const filterHolterEventIndex = {
          studyId,
          profileId,
          types: [type],
          includedEventId: selectedStrip.idEvent,
          ...additionalFilter,
        };
        promiseArr.push(fetchHolterEventIndex(filterHolterEventIndex, false, KEY_CANCEL.API_HOLTER_AI));
      } else {
        promiseArr.push(new Promise((resolve) => resolve(undefined)));
      }
      const [resultHolterEventsPersistAllDay, resultDailyCount, resultEventIndex] = await Promise.allSettled(promiseArr);
      const dailyCount = resultDailyCount?.status === 'rejected' ? undefined : resultDailyCount.value;
      if (resultEventIndex?.status === 'fulfilled') {
        const eventIndex = resultEventIndex.value;
        if (!_.isNil(eventIndex) && eventIndex >= 0) {
          const page = Math.floor(eventIndex / STRIP_EVENT_THUMBNAIL_INFO.stripDisplayLimit);
          await handleFetchStripEvents({ page, additionalFilter });
          promiseUpdateData.current.push(() => setPageIndex({ index: page < 0 ? 0 : page }));
        } else {
          const pageIndex = getPageIndex();
          const { events, eventsCount } = await handleFetchStripEvents({ page: pageIndex.index, additionalFilter });
          if (_.isEmpty(events)) {
            const totalEvent = eventsCount[EVENT_COUNT_CONVERT[getActiveButton()]]?.count || 0;
            const pageTemp = Math.floor(totalEvent / STRIP_EVENT_THUMBNAIL_INFO.stripDisplayLimit);
            const page = (totalEvent % STRIP_EVENT_THUMBNAIL_INFO.stripDisplayLimit) === 0 ? pageTemp - 1 : pageTemp;
            promiseUpdateData.current.push(() => setPageIndex({ index: page < 0 ? 0 : page }));
          } else {
            promiseUpdateData.current.push(() => setPageIndex({ index: getPageIndex().index }));
          }
        }
      }
      if (needUpdateAfibArtifact) {
        handleReloadEventHrChartV2();
      }
      if (!_.isEmpty(dailyCount)) {
        promiseUpdateData.current.push(() => setDailyCount(dailyCount));
      }
      if (!_.includes(promiseUpdateDataType.current, 'setReloadHrChart')) {
        promiseUpdateDataType.current.push('setReloadHrChart');
        promiseUpdateData.current.push(() => setReloadHrChart((prev) => prev + _.round(Math.random() * 100)));
      }
    } catch (error) {
      logError('Failed to fetch reload data: ', error);
      toastrError(error.message, t`Error`);
    }
  };

  const handleReloadEvent = async (msg) => {
    try {
      if (isActiveTab) {
        setIsRenderViewerEcg(false);
      }
      const {
        newEvents, deletedEvents, updatedEvents, deletedEventTypes,
      } = msg;
      const selectedDateValue = getSelectedDateValue();
      const selectedDateString = selectedDateValue ? convertToDayJS(selectedDateValue, timezoneOffset).format('DD-MM-YYYY') : null;
      const types = [TYPE_RHYTHM_EVENT_ENUM.AFIB, TYPE_RHYTHM_EVENT_ENUM.ARTIFACT];
      let needUpdate;
      let needUpdateAfibArtifact; //* Trường hợp sửa artifact hoặc afib xong qua tab event khác save thì hr chart ko update
      if (deletedEventTypes?.length) {
        deletedEventTypes.forEach((type) => {
          if (type === activeButton || type === TYPE_RHYTHM_EVENT_ENUM.TACHY) {
            needUpdate = true;
          } else if (types.includes(type)) {
            needUpdateAfibArtifact = true;
          }
        });
      }
      if (deletedEvents?.length) {
        deletedEvents.forEach((deletedEvent) => {
          if (deletedEvent.type === activeButton || (deletedEvent.type === TYPE_RHYTHM_EVENT_ENUM.TACHY)) {
            needUpdate = true;
          } else {
            const isSameDate = selectedDateString === convertToDayJS(deletedEvent.start, timezoneOffset).format('DD-MM-YYYY');
            if (types.includes(deletedEvent.type) && isSameDate) {
              needUpdateAfibArtifact = true;
            }
          }
        });
      }
      if (newEvents?.length) {
        newEvents.forEach((newEvent) => {
          if (newEvent.type === activeButton) {
            needUpdate = true;
          } else {
            const isSameDate = selectedDateString === convertToDayJS(newEvent.start, timezoneOffset).format('DD-MM-YYYY');
            if (types.includes(newEvent.type) && isSameDate) {
              needUpdateAfibArtifact = true;
            }
          }
        });
      }
      if (updatedEvents?.length) {
        updatedEvents.forEach((updatedEvent) => {
          if (updatedEvent.type === activeButton) {
            needUpdate = true;
          } else {
            const isSameDate = selectedDateString === convertToDayJS(updatedEvent.start, timezoneOffset).format('DD-MM-YYYY');
            if (types.includes(updatedEvent.type) && isSameDate) {
              needUpdateAfibArtifact = true;
            }
          }
        });
      }
      if (needUpdate) {
        await handleReloadEventDataV2(needUpdateAfibArtifact);
      } else if (needUpdateAfibArtifact || activeButton === TYPE_RHYTHM_EVENT_ENUM.AFIB) {
        await handleReloadEventHrChartV2();
      } else if (activeButton === ID_BOOKMARK_TAB) {
        if (!_.includes(promiseUpdateDataType.current, 'setReloadHrChart')) {
          promiseUpdateDataType.current.push('setReloadHrChart');
          promiseUpdateData.current.push(() => setReloadHrChart((prev) => prev + _.round(Math.random() * 100)));
        }
      }
      console.log('[rhythmEventsRecoilDataEffect]-RELOAD-EVENT-RHYTHMEVENT', needUpdate, activeButton, needUpdateAfibArtifact);
      if (!_.includes(promiseUpdateDataType.current, 'setReloadEcgViewer')) {
        promiseUpdateDataType.current.push('setReloadEcgViewer');
        promiseUpdateData.current.push(() => setReloadEcgViewer((prev) => prev + _.round(Math.random() * 100)));
      }
      promiseUpdateData.current.push(() => {
        setGroupEventChanges((prev) => {
          if (prev.length === 0) {
            return prev;
          }
          return [];
        });
        let eventChanges = [];
        let eventNews = [];
        let eventOthers = [];

        setEventChanges((prev) => {
          let count = 0;
          const filterResult = prev.filter((x) => {
            if (x.isSaving) {
              count += 1;
              return false;
            }
            return true;
          });
          if (count === 0) {
            return prev;
          }
          eventChanges.push(...filterResult);
          return filterResult;
        });
        setEventOthers((prev) => {
          let count = 0;
          const filterResult = prev.filter((x) => {
            if (x.isSaving) {
              count += 1;
              return false;
            }
            return true;
          });
          if (count === 0) {
            return prev;
          }
          eventOthers.push(...filterResult);
          return filterResult;
        });
        setEventNews((prev) => {
          let count = 0;
          const filterResult = prev.filter((x) => {
            if (x.isSaving) {
              count += 1;
              return false;
            }
            return true;
          });
          if (count === 0) {
            return prev;
          }
          eventNews.push(...filterResult);
          return filterResult;
        });

        // Perform grouping action applicable to undo/redo
        setEventOptions({
          eventNewsState: eventNews,
          eventChangesState: eventChanges,
          eventOthersState: eventOthers,
        });

        eventChanges = [];
        eventNews = [];
        eventOthers = [];
        const selectedStrip = getSelectedStrip();
        if (selectedStrip?.isNew) {
          setSelectedStrip(null);
        }
      });
    } catch (error) {
      logError('Error: ', error);
    }
    return true;
  };

  const handleUpdateBeats = (msg) => {
    const prevEcgDataMap = getEcgDataMap();
    const cloneEcgDataMap = { ...prevEcgDataMap };
    if ((msg.summaries?.length || msg.beatsUpdated?.summaries?.length) && !_.isEmpty(prevEcgDataMap?.data)) {
      _.forEach(msg.summaries || msg.beatsUpdated?.summaries, (summary) => {
        const foundData = _.find(cloneEcgDataMap.data, (x) => x.id === summary.id);
        if (foundData) {
          _.assign(foundData, {
            avgHrs: summary?.avgHrs,
            maxHrs: summary?.maxHrs,
            minHrs: summary?.minHrs,
            beatFinalPath: summary?.beatFinalPath,
            latestBeatPrefix: summary?.latestBeatPrefix,
          });
        }
      });

      const summaryIds = _.map(msg.summaries || msg.beatsUpdated?.summaries, 'id');
      const socketUpdateEcgDataMap = {
        ...cloneEcgDataMap,
        data: _.filter(cloneEcgDataMap.data, (item) => summaryIds.includes(item.id)),
      };
      if (isActiveTab) {
        emitter.emit(EMITTER_CONSTANTS.UPDATE_SOCKET_BEAT_DATA_MAP, socketUpdateEcgDataMap);
      }
    }
    return cloneEcgDataMap;
  };

  const handleReloadBeat = async (msg) => {
    try {
      const cloneEcgDataMap = handleUpdateBeats(msg);
      promiseUpdateData.current.push(() => {
        let beatsChanges = [];

        setBeatChanges((prev) => {
          if (_.isEmpty(prev)) return prev;
          const beats = removeSavingData(prev);
          beatsChanges = beats;
          return beats;
        });
        setBeatOptions((prev) => ({ ...prev, beatChangesState: beatsChanges }));

        setEcgDataMap((prev) => {
          if (_.isEqual(prev, cloneEcgDataMap)) {
            return prev;
          }
          return cloneEcgDataMap;
        });
        setReloadEcgViewer((prev) => prev + _.round(Math.random() * 100));
      });
    } catch (error) {
      logError('Failed to reload beat', error);
    }
    return true;
  };

  const fetchEventsCount = async () => {
    try {
      const eventsCountFilter = {
        studyId,
        profileId,
      };
      const promises = [
        fetchHolterBeatEventsCount(eventsCountFilter, false, null, false),
        fetchHolterRhythmEventsCount(eventsCountFilter, false, null, false),
      ];
      const [holterBeatEventsCount, holterRhythmEventsCount] = await Promise.all(promises);
      setHolterBeatEventsCount(holterBeatEventsCount);
      setHolterRhythmEventsCount(holterRhythmEventsCount);
    } catch (error) {
      logError('Failed to fetch holter rhythm events count: ', error);
    }
  };

  const updateEventOutOfPending = _.debounce(async () => {
    await clearApolloCache();
    setIsRenderViewerEcg(false);
    setTimeout(() => {
      setIsRenderViewerEcg(true);
    }, 500);
  }, 2000);

  const batchUpdateData = async () => {
    try {
      await clearApolloCache();
      await clearCachesBeatHourly();
      if (isActiveTab || props.activeTab !== '1') {
        setIsRenderViewerEcg(false);
      }
      const promise = [];
      updateDataMessageQueue.current.forEach((x) => {
        if (x.type === AI_COMMAND.EVENT) {
          promise.push(handleReloadEvent(x.msg));
          promise.push(fetchEventsCount());
        }
      });
      const beatPromises = [];
      updateDataMessageQueue.current.forEach((x) => {
        if (x.type === AI_COMMAND.BEAT) {
          beatPromises.push(handleReloadBeat(x.msg));
        }
      });
      await Promise.all(beatPromises); // Wait for all beat promises to resolve
      console.log('[rhythmEventsRecoilDataEffect]-COMMANDEXECUTED-1', {
        promise,
        updateDataMessageQueue: updateDataMessageQueue.current,
        promiseUpdateData: promiseUpdateData.current,
      });
      await Promise.all(promise);
      promiseUpdateData.current.forEach((update) => update());
      updateDataMessageQueue.current.length = 0;
    } catch (error) {
      logError('Error: ', error);
    } finally {
      console.log('[rhythmEventsRecoilDataEffect]-COMMANDEXECUTED-2', {
        updateDataMessageQueue: updateDataMessageQueue.current,
        promiseUpdateData: promiseUpdateData.current,
      });
      updateDataMessageQueue.current.length = 0;
      promiseUpdateData.current.length = 0;
      commandPendingQueue.current.length = 0;
      promiseUpdateDataType.current.length = 0;
      emitter.emit(EMITTER_CONSTANTS.RELOAD_EVENT_STRIP);
      if (isActiveTab) {
        setDoneReset(true);
      }
    }
  };

  useEffect(() => {
    if (doneReset) {
      setTimeout(() => {
        emitter.emit(EMITTER_CONSTANTS.AI_LOADING, {
          isLoading: false,
          tab: 'rhythmEvents',
          isExcuted: isExcutedRef.current,
        });
        setDoneReset(false);
        if (isExcutedRef.current) {
          isExcutedRef.current = false;
        }
      }, 2000);
    }
  }, [doneReset]);

  useEmitter(EMITTER_CONSTANTS.EVENTSUPDATED_EVENT, (msg) => {
    const foundMsg = updateDataMessageQueue.current.find((x) => x.type === AI_COMMAND.EVENT);
    if (foundMsg) {
      if (!_.isEmpty(msg)) {
        Object.keys(msg).forEach((key) => {
          if (foundMsg.msg[key]) {
            foundMsg.msg[key] = foundMsg.msg[key].concat(msg[key]);
          } else {
            foundMsg.msg[key] = msg[key];
          }
        });
      }
    } else {
      updateDataMessageQueue.current.push({
        type: AI_COMMAND.EVENT,
        msg: _.cloneDeep(msg),
      });
    }
    if (commandPendingQueue.current.length === 0) { // update out of pending command
      updateEventOutOfPending();
    }
  }, [studyId, profileId]);

  useEmitter(EMITTER_CONSTANTS.BEATSUPDATED_EVENT, async (msg) => {
    const foundMsg = updateDataMessageQueue.current.find((x) => x.type === AI_COMMAND.BEAT);
    if (foundMsg) {
      if (!_.isEmpty(msg)) {
        _.assign(foundMsg, { msg });
      }
    } else {
      updateDataMessageQueue.current.push({
        type: AI_COMMAND.BEAT,
        msg,
      });
    }
  }, []);

  useEmitter(EMITTER_CONSTANTS.DAILY_SUMMARY_UPDATED, (msg) => {
    setOriginalDailySummaries((prev) => {
      if (msg) {
        const cloneDailySummaries = _.cloneDeep(prev);
        _.forEach(msg, (dailySummary) => {
          const foundDailySummary = _.find(cloneDailySummaries, (x) => x.date === dailySummary.date);
          if (foundDailySummary) {
            _.assign(foundDailySummary, dailySummary);
          }
        });
        return cloneDailySummaries;
      }
      return prev;
    });
  }, []);

  useEmitter(EMITTER_CONSTANTS.AFIB_HR_SUMMARY_UPDATED, (msg) => {
    const { afibAvgHr } = msg;
    setProfileAfibAvgHr(afibAvgHr);
    setUpdatedAfibAvgHr(undefined);
    setUpdatedDailyAfibHrSummaries([]);
  }, []);

  useEmitter(EMITTER_CONSTANTS.AI_PROCESS_SAVED, async (msg) => {
    await batchUpdateData();
    setIsNotReadyAfterSaveTab2(false);
  }, [activeButton, studyId, profileId, isActiveTab, props.activeTab]);

  useEmitter(EMITTER_CONSTANTS.COMMAND_PENDING, (msg) => {
    //* Khi 1 user save, BE gửi command pending về tuỳ theo số lượng api gọi lúc save, push command vào mảng và khi
    // có socket command execute thì remove => khi mảng về 0 thì get hết data nhận đc trong mảng updateDataMessage => update UI
    if (msg.messageId !== profileId) return;
    emitter.emit(EMITTER_CONSTANTS.AI_LOADING, { isLoading: true, tab: 'rhythmEvents' });
    commandPendingQueue.current.push(msg.command);
  }, [profileId]);

  useEmitter(EMITTER_CONSTANTS.COMMAND_EXECUTED, async (msg) => {
    // msg.command: update-events, update-beats, updateHolterHrDailySummary
    // updateHolterProfile, generate-report-comments
    if (msg.messageId !== profileId) return;
    if (msg.command === 'updateHolterProfile' || msg.command === 'generate-report-comments') return;
    console.log('[rhythmEventsRecoilDataEffect]-COMMANDEXECUTED-BEFORE', {
      msg,
      commandPendingQueue: commandPendingQueue.current,
      updateDataMessageQueue: updateDataMessageQueue.current,
    });
    const foundIndexCommand = commandPendingQueue.current.findIndex((command) => command === msg.command);
    if (foundIndexCommand !== -1) {
      commandPendingQueue.current.splice(foundIndexCommand, 1);
    }
    //* Finish all command
    if (commandPendingQueue.current.length === 0) {
      isExcutedRef.current = true;
      if (isActiveTab) {
        if (updateDataMessageQueue.current.length !== 0) {
          //* Announce this tab have data to update
          emitter.emit(EMITTER_CONSTANTS.AI_UPDATE_TAB, '2');
          const { beats, events, strips } = await handleCheckSavingAiProcess({
            studyId,
            profileId,
          });
          if (!beats) {
            setIsNotReadyAfterSaveTab1(true);
          }
          if (!strips) {
            setIsNotReadyAfterSaveTab3(true);
          }
          await batchUpdateData();
        } else {
          setDoneReset(true);
        }
      } else {
        await batchUpdateData();
      }
    }
  }, [activeButton, isActiveTab, studyId, profileId, props.activeTab]);

  return null;
};

export default RhythmEventsRecoilDataEffect;
downloadDownload PNG downloadDownload JPEG downloadDownload SVG

Tip: You can change the style, width & colours of the snippet with the inspect tool before clicking Download!

Click to optimize width for Twitter