import { useEffect, useState } from "react"; import { QueryObserverResult, UseQueryOptions } from "react-query"; import { ListProps } from "antd/lib/list"; import { FormProps } from "antd/lib/form"; import { useForm } from "antd/lib/form/Form"; import { useResourceWithRoute, useList, useSyncWithLocation, useNavigation, useRouterContext, } from "@hooks"; import { ResourceRouterParams, BaseRecord, CrudFilters, CrudSorting, GetListResponse, SuccessErrorNotification, HttpError, MetaDataQuery, LiveModeProps, } from "../../../interfaces"; import { parseTableParams, stringifyTableParams, unionFilters, setInitialFilters, setInitialSorters, unionSorters, } from "@definitions/table"; export type useSimpleListProps = ListProps & { syncWithLocation?: boolean; resource?: string; initialFilter?: CrudFilters; permanentFilter?: CrudFilters; initialSorter?: CrudSorting; permanentSorter?: CrudSorting; onSearch?: ( data: TSearchVariables, ) => CrudFilters | Promise; queryOptions?: UseQueryOptions, TError>; metaData?: MetaDataQuery; } & SuccessErrorNotification & LiveModeProps; export type useSimpleListReturnType< TData extends BaseRecord = BaseRecord, TError extends HttpError = HttpError, TSearchVariables = unknown, > = { listProps: ListProps; queryResult: QueryObserverResult, TError>; searchFormProps: FormProps; filters: CrudFilters; }; /** * By using `useSimpleList` you get props for your records from API in accordance with Ant Design {@link https://ant.design/components/list/ ``} component. * All features such as pagination, sorting come out of the box. * * @see {@link https://refine.dev/docs/api-references/hooks/show/useSimpleList} for more details. * * @typeParam TData - Result data of the query extends {@link https://refine.dev/docs/api-references/interfaceReferences#baserecord `BaseRecord`} * @typeParam TError - Custom error object that extends {@link https://refine.dev/docs/api-references/interfaceReferences#httperror `HttpError`} * @typeParam TSearchVariables - Antd form values * */ export const useSimpleList = < TData extends BaseRecord = BaseRecord, TError extends HttpError = HttpError, TSearchVariables = unknown, >({ resource: resourceFromProp, initialSorter, initialFilter, permanentFilter = [], permanentSorter = [], onSearch, queryOptions, syncWithLocation: syncWithLocationProp, successNotification, errorNotification, liveMode, onLiveEvent, liveParams, metaData, ...listProps }: useSimpleListProps< TData, TError, TSearchVariables > = {}): useSimpleListReturnType => { const { useLocation, useParams } = useRouterContext(); const { resource: routeResourceName } = useParams(); const { push } = useNavigation(); const { search } = useLocation(); const { syncWithLocation: syncWithLocationContext } = useSyncWithLocation(); let syncWithLocation = syncWithLocationProp ?? syncWithLocationContext; const [form] = useForm(); const resourceWithRoute = useResourceWithRoute(); const resource = resourceWithRoute(resourceFromProp ?? routeResourceName); // disable syncWithLocation for custom resource tables if (resourceFromProp) { syncWithLocation = false; } let defaultPageSize = 10; let defaultCurrent = 1; let defaultSorter = initialSorter; let defaultFilter = initialFilter; if (listProps.pagination && listProps.pagination.pageSize) { defaultPageSize = listProps.pagination.pageSize; } if (listProps.pagination && listProps.pagination.current) { defaultCurrent = listProps.pagination.current; } if (syncWithLocation) { const { parsedCurrent, parsedPageSize, parsedSorter, parsedFilters } = parseTableParams(search); defaultCurrent = parsedCurrent || defaultCurrent; defaultPageSize = parsedPageSize || defaultPageSize; defaultSorter = parsedSorter.length ? parsedSorter : defaultSorter; defaultFilter = parsedFilters.length ? parsedFilters : defaultFilter; } const [current, setCurrent] = useState(defaultCurrent); const [pageSize, setPageSize] = useState(defaultPageSize); const [filters, setFilters] = useState( setInitialFilters(permanentFilter, defaultFilter ?? []), ); const [sorter, setSorter] = useState( setInitialSorters(permanentSorter, defaultSorter ?? []), ); useEffect(() => { if (syncWithLocation) { const stringifyParams = stringifyTableParams({ pagination: { current, pageSize, }, sorter, filters, }); return push(`/${resource.route}?${stringifyParams}`); } }, [syncWithLocation, current, pageSize, sorter, filters]); const queryResult = useList({ resource: resource.name, config: { pagination: { current, pageSize, }, filters: unionFilters(permanentFilter, [], filters), sort: unionSorters(permanentSorter, sorter), }, queryOptions, successNotification, errorNotification, liveMode, onLiveEvent, liveParams, metaData, }); const { data, isFetching } = queryResult; const onChange = (page: number, pageSize?: number): void => { setCurrent(page); setPageSize(pageSize || 10); }; const onFinish = async (values: TSearchVariables) => { if (onSearch) { const searchFilters = await onSearch(values); setCurrent(1); return setFilters((prevFilters) => unionFilters(permanentFilter, searchFilters, prevFilters), ); } }; return { searchFormProps: { form, onFinish, }, listProps: { ...listProps, dataSource: data?.data, loading: isFetching, pagination: { ...listProps.pagination, total: data?.total, pageSize, current, onChange, }, }, queryResult, filters, }; };