All files / src/components/Merchants/MerchantPreview/RiskProfile/hooks useRiskActivity.ts

92.3% Statements 36/39
66.66% Branches 24/36
100% Functions 12/12
94.44% Lines 34/36

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173                            20x                               20x         25x   25x           20x         73x   73x                           73x     25x               119x 119x 119x                 73x     25x                             73x 46x 21x       73x 46x 335x       73x           73x 46x                   73x 46x   46x 46x 46x       73x   73x 46x 46x                     73x   73x                          
import { useInView } from "react-intersection-observer";
import { customInstance } from "@services/api";
import { useEffect, useMemo, useState } from "react";
import { useInfiniteQuery, useQuery } from "react-query";
import { riskActivitiesParser } from "../helpers/parsers";
import { TRiskActivity } from "../types";
import getMerchantRiskProfile from "@components/Merchants/MerchantPreview/RiskProfile/hooks/getMerchantRiskProfileQuery";
import {
  GENERAL_STALE_TIME_15,
  MERCHANT_SIDE_PANEL_PREVIEW_API_KEYS,
} from "@features/Merchants/MerchantSidePanel/constants";
import { QKEY_GET_ACTIVE_RISK_ACTIVITIES } from "@constants/queryKeys";
import { ROWS_PER_PAGE } from "@hooks/common/usePagination";
 
const tabs = {
  ALL: "All",
  ACTIVE: "Active",
};
 
type TActiveRiskResponse = {
  total: number;
  data: TRiskActivity[];
};
 
type RiskActivityQueryProp = {
  profileId: number;
  merchantId: number;
  activeRisksSort?: string;
};
 
const getActiveRisks = ({
  profileId,
  merchantId,
  activeRisksSort,
}: RiskActivityQueryProp) => {
  const sortQuerry = `sort=${activeRisksSort}`;
 
  return customInstance({
    url: `/merchants/${merchantId}/risk/merchant-profiles/${profileId}/escalations?filter=isIgnored:false&${sortQuerry}`,
    method: "GET",
  });
};
 
export const useRiskActivity = ({
  profileId,
  merchantId,
  activeRisksSort = "-createdAt",
}: RiskActivityQueryProp) => {
  const [activeTab, setActiveTab] = useState(tabs.ALL);
 
  const queryKey = [
    MERCHANT_SIDE_PANEL_PREVIEW_API_KEYS.RISK_ACTIVITIES,
    profileId,
    merchantId,
  ];
 
  const {
    data: infiniteData,
    isLoading,
    isFetching,
    isFetchingNextPage,
    hasNextPage,
    fetchNextPage,
    isError,
  } = useInfiniteQuery(
    queryKey,
    async ({ pageParam = 1 }) => {
      return await getMerchantRiskProfile(profileId, pageParam, merchantId);
    },
    {
      enabled: !!profileId && !!merchantId,
      refetchOnWindowFocus: false,
      staleTime: GENERAL_STALE_TIME_15,
      refetchOnMount: false,
      getNextPageParam: (lastPage, allPages) => {
        const totalPages = Math.ceil((lastPage?.total ?? 0) / ROWS_PER_PAGE);
        const nextPage = allPages.length + 1;
        return nextPage <= totalPages ? nextPage : undefined;
      },
    },
  );
 
  const {
    isLoading: isActiveRisksLoading,
    isFetching: isActiveRisksFetching,
    data: activeRisks,
  } = useQuery<TActiveRiskResponse>(
    [QKEY_GET_ACTIVE_RISK_ACTIVITIES, profileId, merchantId],
    async () => {
      return await getActiveRisks({
        profileId,
        merchantId,
        activeRisksSort,
      });
    },
    {
      enabled: !!profileId && !!merchantId,
      refetchOnWindowFocus: false,
      staleTime: GENERAL_STALE_TIME_15,
      refetchOnMount: false,
    },
  );
 
  // Flatten all pages into a single array
  const allActivities = useMemo(() => {
    if (!infiniteData?.pages) return [];
    return infiniteData.pages.flatMap((page) => page?.data || []);
  }, [infiniteData]);
 
  // Remove duplicates by id
  const uniqueActivities = useMemo(() => {
    return Array.from(
      new Map(allActivities.map((item) => [item.id, item])).values(),
    );
  }, [allActivities]);
 
  const { ref: targetRef, inView } = useInView({
    threshold: 0.1,
    triggerOnce: false,
  });
 
  // Fetch next page when target element is in view
  useEffect(() => {
    Iif (
      inView &&
      hasNextPage &&
      !isFetchingNextPage &&
      activeTab === tabs.ALL
    ) {
      fetchNextPage();
    }
  }, [inView, hasNextPage, isFetchingNextPage, fetchNextPage, activeTab]);
 
  const activities = useMemo(() => {
    const list = riskActivitiesParser(uniqueActivities) as TRiskActivity[];
    const activeList =
      (activeRisks?.data && riskActivitiesParser(activeRisks?.data)) || [];
    Iif (activeTab === tabs.ACTIVE) return activeList;
    return list;
  }, [activeTab, uniqueActivities, activeRisks]);
 
  const isAllRiskActivityLoading =
    isLoading || (!activities?.length && isFetching);
 
  const isLoadingNextPage = useMemo(() => {
    Eif (activeTab === tabs.ALL) {
      return isFetchingNextPage;
    }
    return isActiveRisksFetching && activities.length !== activeRisks?.total;
  }, [
    activeTab,
    isFetchingNextPage,
    isActiveRisksFetching,
    activities.length,
    activeRisks?.total,
  ]);
 
  const total = infiniteData?.pages?.[0]?.total ?? 0;
 
  return {
    total,
    data: activities as TRiskActivity[],
    isLoading: isAllRiskActivityLoading || isActiveRisksLoading,
    isError,
    targetRef,
    tabs,
    activeTab,
    setActiveTab,
    activeRisks: activeRisks?.data,
    isLoadingNextPage: isLoadingNextPage,
  };
};