import { useEffect, useRef } from 'react' import { flattenConversationPages, flattenPostPages, focalPostFromPages, } from '../page' import type { Post } from '../types' import { type FeedRequest, PostLoadError, usePostFeed } from '../use-post-feed' import { PostCard } from './post-card' function FocalPost({ post }: { post: Post }) { return (

表示中の投稿

) } export function PostFeed({ request }: { request: FeedRequest | undefined }) { const query = usePostFeed(request) const sentinel = useRef(null) const pages = query.data?.pages ?? [] const focalPost = request?.kind === 'thread' ? focalPostFromPages(pages) : undefined const posts = focalPost ? flattenConversationPages(pages, focalPost.id) : flattenPostPages(pages) useEffect(() => { if ( !sentinel.current || !query.hasNextPage || query.isFetchNextPageError || query.isFetchingNextPage ) { return } let requested = false const observer = new IntersectionObserver( ([entry]) => { if (entry?.isIntersecting && !requested) { requested = true void query.fetchNextPage() } }, { rootMargin: '600px 0px' }, ) observer.observe(sentinel.current) return () => observer.disconnect() }, [ query.fetchNextPage, query.hasNextPage, query.isFetchNextPageError, query.isFetchingNextPage, ]) if (!request) return null if (query.isPending) { return (

投稿を取得しています…

) } if (query.isError && !query.isFetchNextPageError && posts.length === 0) { const error = query.error instanceof PostLoadError ? query.error.detail : { message: '投稿を取得できませんでした。', retryable: true } return (

{error.message}

{error.retryable ? ( ) : null}
) } if (posts.length === 0 && !query.hasNextPage) { return ( <> {focalPost ? : null}

{focalPost ? '会話にほかの投稿はありません。' : '条件に一致する投稿はありません。'}

) } return ( <> {focalPost ? : null}
{posts.map((post) => ( ))}
) }