All files / src/sections/PayBuilder/components/hooks useCheckFormType.ts

96.87% Statements 31/32
95.83% Branches 23/24
100% Functions 4/4
96.77% Lines 30/31

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                      469x 15894x 15893x 15893x 15893x     15893x 15893x 15893x 15893x             15893x       15893x           15893x     15893x       41x     41x                             15893x       15894x 15894x 15894x   15894x 15893x             107307x   15893x     15893x 15893x 15893x 15893x 15893x   15893x   15893x                        
import { useLocation, useParams } from "react-router-dom";
import { TPublicForm } from "./types";
import { useQuery, useQueryClient } from "react-query";
import { useAppSelector } from "@redux/hooks";
import { selectPaymentFormID } from "@redux/slices/products";
import { CampaignMapperValues } from "features/Minibuilders/PaymentFormMinibuilder/useCreateCampaignFn";
import { FormType, useGetRebrandedFormTypes } from "@sections/PayBuilder/utils";
import { customInstance } from "@services/api";
 
// this hook aims to get form data of the current form in view
 
export const useGetFormData = () => {
  const queryClient = useQueryClient();
  const { state } = useLocation();
  const { id } = useParams();
  const isValidId = Boolean(Number(id)) && !!id && !isNaN(Number(id));
 
  // We are adding isNaN check to only use pathaname if we have id(number)
  const idFromPathName = Number(location.pathname.slice(1));
  const idToUse = isNaN(idFromPathName) ? id : String(idFromPathName);
  const peekedFormId = useAppSelector(selectPaymentFormID);
  const formId = idToUse || state?.id || peekedFormId;
 
  /**
   * CRITICAL FIX: Check if data already exists in cache BEFORE making a query.
   * useGetPublicForm (at the top level) is the primary data fetcher.
   * This hook should only read from cache, not trigger additional API calls.
   */
  const existingPublicData = queryClient.getQueryData<TPublicForm>([
    "public-form-id",
    id,
  ]);
  const loggedUserFormData = queryClient.getQueryData<TPublicForm>([
    "get-payment-form-by-id",
    formId,
  ]);
 
  // If we already have data in cache, don't make another query
  const hasExistingData = existingPublicData || loggedUserFormData;
 
  // when user is not logged in we have this form data
  const { data: publicData, isLoading } = useQuery({
    queryKey: ["public-form-id", id],
    queryFn: async () => {
      // Safety check: should never execute with invalid ID due to enabled check
      Iif (!isValidId) {
        throw new Error(`Invalid product ID: ${id}`);
      }
      return customInstance({
        url: `/products/${id}`,
      });
    },
    // CRITICAL: Only enable if we have a valid ID AND don't have cached data
    enabled: isValidId && !hasExistingData,
    // If we have existing data, use it immediately
    initialData: existingPublicData,
    // Prevent duplicate API calls when multiple components mount
    staleTime: 1000 * 60 * 2, // Consider data fresh for 2 minutes
    cacheTime: 1000 * 60 * 5, // Keep in cache for 5 minutes
    // Don't retry on invalid IDs
    retry: false,
  });
 
  return { data: publicData || loggedUserFormData, isLoading };
};
 
export default function useCheckFormType() {
  const { search, state } = useLocation();
  const searchParams = new URLSearchParams(search);
  const rebrandedFormTypes = useGetRebrandedFormTypes();
  // tot get data from API and when data is from API we use it instead of the useLocation values
  const { data, isLoading } = useGetFormData();
  const type: CampaignMapperValues = data?.typeName
    ? data?.typeName
    : searchParams.get("type") ||
      state?.campaignName ||
      state?.campaign ||
      state?.campaignType;
 
  const isFormType = (formType: FormType) => type === formType;
 
  const isFundraiser = isFormType(FormType.FUNDRAISERS);
  // This change is added since in BE it's called standard and in FE it's product. TODO: refactor
  const isProduct =
    isFormType(FormType.STANDARDS) || isFormType(FormType.PRODUCTS);
  const isEvent = isFormType(FormType.EVENTS);
  const isSweepstake = isFormType(FormType.SWEEPSTAKE);
  const isMembership = isFormType(FormType.MEMBERSHIPS);
  const isInvoice = isFormType(FormType.INVOICES);
 
  const isNewCustomerViewForm = rebrandedFormTypes.includes(type);
 
  return {
    isFundraiser,
    isProduct,
    isEvent,
    isMembership,
    formType: type,
    isNewCustomerViewForm,
    isSweepstake,
    isInvoice,
    isLoading,
  };
}