teamdigitale/italia-app

View on GitHub
ts/utils/hooks/useLoadPotValue.ts

Summary

Maintainability
A
1 hr
Test Coverage
/* eslint-disable functional/immutable-data */
import { useNavigation } from "@react-navigation/native";
import * as pot from "@pagopa/ts-commons/lib/pot";
import { Millisecond } from "@pagopa/ts-commons/lib/units";
import { useCallback, useEffect, useRef, useState } from "react";

const retryTimeout = 5000 as Millisecond;

/**
 * Load the pot value using the loadAction until is some. Automatically retry using the {@link retryTimeout}
 * @param id - the loadRequestId. Should be always the same for the same pot and different, for different pots.
 * @param potValue - the value that we would ensure that should be loaded
 * @param loadAction - the action that trigger the load of the pot
 */
export const useLoadPotValue = <T, E>(
  id: string,
  potValue: pot.Pot<T, E>,
  loadAction: () => void
) => {
  const [idState, setId] = useState("");
  const timerRetry = useRef<number | undefined>(undefined);
  const navigation = useNavigation();
  const retry = useCallback(() => {
    timerRetry.current = undefined;
    loadAction();
  }, [loadAction]);
  const isFocused = navigation.isFocused();

  /**
   * When the focus change or the idRequest changes, clear the timer (if any)
   * and reset the value to undefined.
   * focus: true  -> a new schedule is allowed
   * focus: false -> clear all the pending schedule
   */
  useEffect(() => {
    clearTimeout(timerRetry.current);
    timerRetry.current = undefined;
  }, [isFocused, idState]);

  useEffect(() => {
    setId(id);
    // Initial state, request the state
    if (potValue === pot.none) {
      loadAction();
    } else if (
      pot.isNone(potValue) &&
      pot.isError(potValue) &&
      timerRetry.current === undefined &&
      isFocused
    ) {
      // If the pot is NoneError, the navigation focus is on the element
      // and no other retry are scheduled
      timerRetry.current = setTimeout(retry, retryTimeout);
    }
  }, [potValue, isFocused, idState, id, loadAction, retry]);

  // Component unmount, clear scheduled
  useEffect(
    () => () => {
      clearTimeout(timerRetry.current);
    },
    []
  );
};