'use client' import qs from 'qs' import React, { Fragment, useCallback, useEffect, useRef, useState } from 'react' import type { Post } from '../../../../../test/live-preview/payload-types.js' import type { ArchiveBlockProps } from '../../../_blocks/ArchiveBlock/types.js' import { PAYLOAD_SERVER_URL } from '../../../_api/serverURL.js' import { Card } from '../../Card/index.js' import { Gutter } from '../../Gutter/index.js' import { PageRange } from '../../PageRange/index.js' import { Pagination } from '../../Pagination/index.js' import classes from './index.module.scss' type Result = { docs: (Post | string)[] hasNextPage: boolean hasPrevPage: boolean nextPage: number page: number prevPage: number totalDocs: number totalPages: number } export type Props = Omit & { className?: string onResultChange?: (result: Result) => void // eslint-disable-line no-unused-vars showPageRange?: boolean sort?: string } export const CollectionArchiveByCollection: React.FC = (props) => { const { categories: catsFromProps, className, limit = 10, onResultChange, populatedDocs, populatedDocsTotal, relationTo, showPageRange, sort = '-createdAt', } = props const [results, setResults] = useState({ docs: populatedDocs?.map((doc) => doc.value) || [], hasNextPage: false, hasPrevPage: false, nextPage: 1, page: 1, prevPage: 1, totalDocs: typeof populatedDocsTotal === 'number' ? populatedDocsTotal : 0, totalPages: 1, }) const [isLoading, setIsLoading] = useState(false) const [error, setError] = useState(undefined) const scrollRef = useRef(null) const hasHydrated = useRef(false) const [page, setPage] = useState(1) const scrollToRef = useCallback(() => { const { current } = scrollRef if (current) { // current.scrollIntoView({ // behavior: 'smooth', // }) } }, []) useEffect(() => { if (!isLoading && typeof results.page !== 'undefined') { // scrollToRef() } }, [isLoading, scrollToRef, results]) useEffect(() => { // hydrate the block with fresh content after first render // don't show loader unless the request takes longer than x ms // and don't show it during initial hydration const timer = setTimeout(() => { if (hasHydrated) { setIsLoading(true) } }, 500) const searchQuery = qs.stringify( { depth: 1, limit, page, sort, where: { ...(catsFromProps && catsFromProps?.length > 0 ? { categories: { in: typeof catsFromProps === 'string' ? [catsFromProps] : catsFromProps .map((cat) => (typeof cat === 'object' && cat !== null ? cat.id : cat)) .join(','), }, } : {}), }, }, { encode: false }, ) const makeRequest = async () => { try { const req = await fetch(`${PAYLOAD_SERVER_URL}/api/${relationTo}?${searchQuery}`) const json = await req.json() clearTimeout(timer) hasHydrated.current = true const { docs } = json as { docs: Post[] } if (docs && Array.isArray(docs)) { setResults(json) setIsLoading(false) if (typeof onResultChange === 'function') { onResultChange(json) } } } catch (err) { console.warn(err) // eslint-disable-line no-console setIsLoading(false) setError(`Unable to load "${relationTo} archive" data at this time.`) } } void makeRequest() return () => { if (timer) clearTimeout(timer) } }, [page, catsFromProps, relationTo, onResultChange, sort, limit]) return (
{!isLoading && error && {error}} {showPageRange !== false && (
)}
{results.docs?.map((result, index) => { if (typeof result === 'string') { return null } return (
) })}
{results.totalPages > 1 && ( )}
) }