Compare commits

...

10 Commits

Author SHA1 Message Date
Germán Jabloñski
a3e0a45f3a save 2025-01-10 20:00:22 -03:00
Germán Jabloñski
6d040ac2c3 revert _community repro 2025-01-10 19:58:12 -03:00
Germán Jabloñski
9e18737a40 add select to query 2025-01-10 19:53:59 -03:00
Germán Jabloñski
351206813e remove more unused code 2025-01-10 19:45:12 -03:00
Germán Jabloñski
f084197948 fixed!! 2025-01-10 19:39:49 -03:00
Germán Jabloñski
75b3189a07 remove unused types 2025-01-10 18:06:26 -03:00
Germán Jabloñski
a9e7243dcd replace like with contains 2025-01-10 16:14:43 -03:00
Germán Jabloñski
b7db325c12 remove unused callback 2025-01-10 16:11:22 -03:00
Germán Jabloñski
adfaa939f5 improve repro 2025-01-10 16:09:07 -03:00
Germán Jabloñski
82537ffd37 filter pagination bug 2025-01-10 11:25:21 -03:00
2 changed files with 13 additions and 123 deletions

View File

@@ -1,5 +1,5 @@
'use client'
import type { ClientCollectionConfig, PaginatedDocs, Where } from 'payload'
import type { ClientCollectionConfig, PaginatedDocs } from 'payload'
import * as qs from 'qs-esm'
import React, { useCallback, useEffect, useReducer, useState } from 'react'
@@ -16,7 +16,7 @@ import optionsReducer from './optionsReducer.js'
const baseClass = 'condition-value-relationship'
const maxResultsPerRequest = 10
const maxResultsPerRequest = 50
export const RelationshipField: React.FC<Props> = (props) => {
const {
@@ -39,23 +39,13 @@ export const RelationshipField: React.FC<Props> = (props) => {
const [options, dispatchOptions] = useReducer(optionsReducer, [])
const [search, setSearch] = useState('')
const [errorLoading, setErrorLoading] = useState('')
const [hasLoadedFirstOptions, setHasLoadedFirstOptions] = useState(false)
const debouncedSearch = useDebounce(search, 300)
const { i18n, t } = useTranslation()
const relationSlugs = hasMultipleRelations ? relationTo : [relationTo]
const initialRelationMap = () => {
const map: Map<string, number> = new Map()
relationSlugs.forEach((relation) => {
map.set(relation, 1)
})
return map
}
const nextPageByRelationshipRef = React.useRef<Map<string, number>>(initialRelationMap())
const partiallyLoadedRelationshipSlugs = React.useRef<string[]>(relationSlugs)
const addOptions = useCallback(
const setOptions = useCallback(
(data, relation) => {
const collection = getEntityConfig({ collectionSlug: relation }) as ClientCollectionConfig
dispatchOptions({ type: 'CLEAR', i18n, required: false })
dispatchOptions({ type: 'ADD', collection, data, hasMultipleRelations, i18n, relation })
},
[hasMultipleRelations, i18n, getEntityConfig],
@@ -69,22 +59,18 @@ export const RelationshipField: React.FC<Props> = (props) => {
abortController: AbortController
relationSlug: string
}) => {
if (relationSlug && partiallyLoadedRelationshipSlugs.current.includes(relationSlug)) {
if (relationSlug) {
const collection = getEntityConfig({
collectionSlug: relationSlug,
}) as ClientCollectionConfig
const fieldToSearch = collection?.admin?.useAsTitle || 'id'
const pageIndex = nextPageByRelationshipRef.current.get(relationSlug)
const query: {
depth?: number
limit?: number
page?: number
where: Where
} = {
const query = {
depth: 0,
limit: maxResultsPerRequest,
page: pageIndex,
select: {
[fieldToSearch]: true,
},
where: {
and: [],
},
@@ -113,18 +99,7 @@ export const RelationshipField: React.FC<Props> = (props) => {
if (response.ok) {
const data: PaginatedDocs = await response.json()
if (data.docs.length > 0) {
addOptions(data, relationSlug)
if (!debouncedSearch) {
if (data.nextPage) {
nextPageByRelationshipRef.current.set(relationSlug, data.nextPage)
} else {
partiallyLoadedRelationshipSlugs.current =
partiallyLoadedRelationshipSlugs.current.filter(
(partiallyLoadedRelation) => partiallyLoadedRelation !== relationSlug,
)
}
}
setOptions(data, relationSlug)
}
} else {
setErrorLoading(t('error:unspecific'))
@@ -135,22 +110,10 @@ export const RelationshipField: React.FC<Props> = (props) => {
}
}
}
setHasLoadedFirstOptions(true)
},
[addOptions, api, collections, debouncedSearch, i18n.language, serverURL, t],
[setOptions, api, collections, debouncedSearch, i18n.language, serverURL, t],
)
const loadMoreOptions = React.useCallback(() => {
if (partiallyLoadedRelationshipSlugs.current.length > 0) {
const abortController = new AbortController()
void loadRelationOptions({
abortController,
relationSlug: partiallyLoadedRelationshipSlugs.current[0],
})
}
}, [loadRelationOptions])
const findOptionsByValue = useCallback((): Option | Option[] => {
if (value) {
if (hasMany) {
@@ -208,37 +171,6 @@ export const RelationshipField: React.FC<Props> = (props) => {
return undefined
}, [hasMany, hasMultipleRelations, value, options])
const handleInputChange = useCallback(
(newSearch) => {
if (search !== newSearch) {
setSearch(newSearch)
}
},
[search],
)
const addOptionByID = useCallback(
async (id, relation) => {
if (!errorLoading && id !== 'null' && id && relation) {
const response = await fetch(`${serverURL}${api}/${relation}/${id}?depth=0`, {
credentials: 'include',
headers: {
'Accept-Language': i18n.language,
},
})
if (response.ok) {
const data = await response.json()
addOptions({ docs: [data] }, relation)
} else {
// eslint-disable-next-line no-console
console.error(t('error:loadingDocument', { id }))
}
}
},
[i18n, addOptions, api, errorLoading, serverURL, t],
)
/**
* 1. Trigger initial relationship options fetch
* 2. When search changes, loadRelationOptions will
@@ -269,47 +201,6 @@ export const RelationshipField: React.FC<Props> = (props) => {
}
}, [i18n, loadRelationOptions, relationTo])
/**
* Load any options that were not returned
* in the first 10 of each relation fetch
*/
useEffect(() => {
if (value && hasLoadedFirstOptions) {
if (hasMany) {
const matchedOptions = findOptionsByValue()
;((matchedOptions as Option[]) || []).forEach((option, i) => {
if (!option) {
if (hasMultipleRelations) {
void addOptionByID(value[i].value, value[i].relationTo)
} else {
void addOptionByID(value[i], relationTo)
}
}
})
} else {
const matchedOption = findOptionsByValue()
if (!matchedOption) {
if (hasMultipleRelations) {
const valueWithRelation = value as ValueWithRelation
void addOptionByID(valueWithRelation.value, valueWithRelation.relationTo)
} else {
void addOptionByID(value, relationTo)
}
}
}
}
}, [
addOptionByID,
findOptionsByValue,
hasMany,
hasMultipleRelations,
relationTo,
value,
hasLoadedFirstOptions,
])
const classes = ['field-type', baseClass, errorLoading && 'error-loading']
.filter(Boolean)
.join(' ')
@@ -352,8 +243,7 @@ export const RelationshipField: React.FC<Props> = (props) => {
onChange(selected?.value)
}
}}
onInputChange={handleInputChange}
onMenuScrollToBottom={loadMoreOptions}
onInputChange={setSearch}
options={options}
placeholder={t('general:selectValue')}
value={valueToRender}

View File

@@ -336,4 +336,4 @@ export interface Auth {
declare module 'payload' {
// @ts-ignore
export interface GeneratedTypes extends Config {}
}
}