import React, { ReactNode } from 'react'; import { ResourceContextProvider } from '../../core'; import { ListContextProvider } from '../list/ListContextProvider'; import { useReferenceManyFieldController, type UseReferenceManyFieldControllerParams, } from './useReferenceManyFieldController'; import type { RaRecord } from '../../types'; import { ListControllerResult } from '../list'; /** * Render related records to the current one. * * You must define the fields to be passed to the iterator component as children. * * @example Display all the comments of the current post as a datagrid * * * * * * * * * * @example Display all the books by the current author, only the title * * * * * * * By default, restricts the displayed values to 25. You can extend this limit * by setting the `perPage` prop. * * @example * * ... * * * By default, orders the possible values by id desc. You can change this order * by setting the `sort` prop (an object with `field` and `order` properties). * * @example * * ... * * * Also, you can filter the query used to populate the possible values. Use the * `filter` prop for that. * * @example * * ... * */ export const ReferenceManyFieldBase = < RecordType extends RaRecord = RaRecord, ReferenceRecordType extends RaRecord = RaRecord, >( props: ReferenceManyFieldBaseProps ) => { const { children, render, debounce, empty, error, loading, filter = defaultFilter, exporter, offline, page = 1, perPage = 25, record, reference, resource, sort = defaultSort, source = 'id', storeKey, target, queryOptions, } = props; const controllerProps = useReferenceManyFieldController< RecordType, ReferenceRecordType >({ debounce, filter, exporter, page, perPage, record, reference, resource, sort, source, storeKey, target, queryOptions, }); if (!render && !children) { throw new Error( " requires either a 'render' prop or 'children' prop" ); } const { data, error: controllerError, filterValues, hasNextPage, hasPreviousPage, isPaused, isPending, isPlaceholderData, total, } = controllerProps; const shouldRenderLoading = isPending && !isPaused && loading !== false && loading !== undefined; const shouldRenderOffline = isPaused && (isPending || isPlaceholderData) && offline !== false && offline !== undefined; const shouldRenderError = controllerError && error !== false && error !== undefined; const shouldRenderEmpty = empty !== false && empty !== undefined && // there is no error !error && // the list is not loading data for the first time !isPending && // the API returned no data (using either normal or partial pagination) (total === 0 || (total == null && // @ts-ignore FIXME total may be undefined when using partial pagination but the ListControllerResult type is wrong about it hasPreviousPage === false && // @ts-ignore FIXME total may be undefined when using partial pagination but the ListControllerResult type is wrong about it hasNextPage === false && // @ts-ignore FIXME total may be undefined when using partial pagination but the ListControllerResult type is wrong about it data.length === 0)) && // the user didn't set any filters !Object.keys(filterValues).length; return ( {shouldRenderLoading ? loading : shouldRenderOffline ? offline : shouldRenderError ? error : shouldRenderEmpty ? empty : render ? render(controllerProps) : children} ); }; export interface ReferenceManyFieldBaseProps< RecordType extends Record = Record, ReferenceRecordType extends RaRecord = RaRecord, > extends UseReferenceManyFieldControllerParams< RecordType, ReferenceRecordType > { children?: ReactNode; render?: (props: ListControllerResult) => ReactNode; empty?: ReactNode; error?: ReactNode; loading?: ReactNode; offline?: ReactNode; } const defaultFilter = {}; const defaultSort = { field: 'id', order: 'DESC' as const };