All files / src/pages/EmailVerification/api useResendEmail.ts

82.35% Statements 14/17
66.66% Branches 10/15
100% Functions 4/4
100% Lines 14/14

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                  13x                               13x 1x 1x 1x 1x     13x 394x   3x             2x 2x       1x 1x             394x                        
import { AxiosError } from "axios";
import Cookies from "js-cookie";
import { customInstance } from "@services/api";
import { RESEND_EMAIL_URL } from "@services/api/api.constant";
import { useMutation } from "react-query";
import { showMessage } from "@common/Toast/ShowToast";
 
export { RESEND_EMAIL_URL } from "@services/api/api.constant";
export const RESEND_ERROR_MESSAGE =
  "We could not resend the email. Please start the purchase again.";
 
type TData = {
  orderID: number;
};
 
type TResendError = { message?: string; code?: string };
 
type TResendOptions = {
  /** Callers that surface the failure themselves, e.g. inline in a modal. */
  reportErrors?: boolean;
};
 
// Mirrors the interceptor's own branches, each with that branch's conditions:
// claiming one it does not take leaves the failure on no screen at all. Its 400
// toast is suppressed for this endpoint, so this hook owns those.
const isReportedByInterceptor = (error: AxiosError<TResendError>) => {
  const status = error?.response?.status;
  const code = error?.response?.data?.code;
  Iif (status === 401) return code === "not_authenticated";
  return status === 403 && code === "not_authorized" && !!Cookies.get("user");
};
 
const useResendEmail = ({ reportErrors = true }: TResendOptions = {}) => {
  const { isLoading, mutate, mutateAsync, isSuccess, isError } = useMutation(
    async (data: TData) => {
      const result = await customInstance({
        url: RESEND_EMAIL_URL,
        method: "POST",
        data,
      });
      // A canceled or aborted write resolves null instead of rejecting, which
      // would read as a mail that went out and restart the caller's cooldown.
      Iif (result === null) throw new Error("verification email not sent");
      return result;
    },
    {
      onError: (error: AxiosError<TResendError>) => {
        Iif (!reportErrors || isReportedByInterceptor(error)) return;
        showMessage(
          "Error",
          error?.response?.data?.message || RESEND_ERROR_MESSAGE,
        );
      },
    },
  );
  return {
    sendEmail: mutate,
    // Rejects on failure, so a caller can tell a mail that went out from one
    // that did not.
    sendEmailAsync: mutateAsync,
    isLoading: isLoading,
    isSuccess: isSuccess,
    isError: isError,
  };
};
 
export { useResendEmail, type TData };