Untitled

src\modules\main\components\table\hooks\table.hook.ts
mail@pastecode.io avatar
unknown
plain_text
a year ago
2.6 kB
2
Indexable
Never
import { PlanningStatus } from '@/modules/shared/consts';
import { useAppDispatch, useAppSelector } from '@/store/hooks';
import { ActionCreatorWithPayload, AsyncThunk, CombinedState } from '@reduxjs/toolkit';
import { useEffect, useMemo } from 'react';
import { useForm, UseFormReturn } from 'react-hook-form';
import { StoreType } from '../../../../../store';
import { EntityState } from './../../../pages/settings/redux/entity-state.type';
import { IdentifiableEntity, IdType } from './../../../pages/settings/redux/thunks';

interface UseTableDataType<Entity, EntityMapped extends IdentifiableEntity> {
  loading: boolean | undefined;
  uiData: EntityMapped[];
  data: Entity[];
  form: UseFormReturn<{ search: string; status: number | string | undefined }, any>;
}

interface UseTableDataProps<Entity, EntityMapped extends IdentifiableEntity, SingleEntity> {
  filterThunk: ActionCreatorWithPayload<string, string>;
  readThunk: AsyncThunk<Entity[], IdType, Record<string, unknown>>;
  stateSelector: (state: CombinedState<StoreType>) => EntityState<Entity, SingleEntity>;
  mapEntityToUiData: (entity: Entity) => EntityMapped;
  shouldFilterByStatus?: boolean;
}

export const useTableData = <Entity, EntityMapped extends IdentifiableEntity, SingleEntity>({
  filterThunk,
  readThunk,
  stateSelector,
  mapEntityToUiData,
  shouldFilterByStatus = false,
}: UseTableDataProps<Entity, EntityMapped & IdentifiableEntity, SingleEntity>): UseTableDataType<
  Entity,
  EntityMapped & IdentifiableEntity
> => {
  const dispatch = useAppDispatch();
  const form = useForm<{ search: string; status: number | string | undefined }>({
    defaultValues: {
      search: '',
      status: 1,
    },
  });
  const { search, status } = form.watch();

  useEffect(() => {
    dispatch(filterThunk(search));
  }, [search, dispatch, filterThunk]);

  const { filtered, loading, data } = useAppSelector(stateSelector);
  const filteredByText: EntityMapped[] = useMemo(
    () => filtered.map(mapEntityToUiData),
    [filtered, mapEntityToUiData],
  );

  const filterUiDataByStatus = (): EntityMapped[] => {
    if (status === 1 || !shouldFilterByStatus) return filteredByText;
    const filteredByStatus = filteredByText.filter((entity: EntityMapped) => {
      return entity.status?.toString().toLowerCase() === PlanningStatus[status as number];
    });

    return filteredByStatus;
  };

  const uiData = filterUiDataByStatus();

  useEffect(() => {
    dispatch(readThunk());
  }, [dispatch, readThunk]);

  return {
    loading,
    uiData,
    data,
    form,
  };
};