import { queryRecordParams } from '@/lib/queryState' import { useQuery } from '@tanstack/react-query' import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react' import { useLocation } from 'react-router-dom' import { useLocale, useLocaleNavigate } from '@/lib/useLocale' import PostList from '@/components/PostList' import PrefetchLink from '@/components/PrefetchLink' import TagSidebar from '@/components/TagSidebar' import WikiBody from '@/components/WikiBody' import Pagination from '@/components/common/Pagination' import TabGroup, { Tab } from '@/components/common/TabGroup' import MainArea from '@/components/layout/MainArea' import PageHead from '@/components/common/PageHead' import { fetchPosts } from '@/lib/posts' import { localeLanguage } from '@/lib/locales' import { postsKeys } from '@/lib/queryKeys' import { DEFAULT_POST_LIST_LIMIT, getClientListLimit, LIST_LIMIT_OPTIONS, setClientListSettings, } from '@/lib/settings' import { useKeyboardShortcuts } from '@/lib/useKeyboardShortcuts' import { fetchWikiPageByTitle } from '@/lib/wiki' import { useUITranslation } from '@/lib/useUITranslation' import { useHydrated } from '@/lib/useHydrated' import type { FC } from 'react' import type { WikiPage } from '@/types' const parseLimit = (value: string | null): 20 | 50 | 100 | null => { const n = Number (value) return n === 20 || n === 50 || n === 100 ? n : null } const PostListPage: FC = () => { const locale = useLocale () const hydrated = useHydrated () const { message, label, siteTitle } = useUITranslation ('posts') const containerRef = useRef (null) const [wikiPage, setWikiPage] = useState (null) const location = useLocation () const navigate = useLocaleNavigate () const query = new URLSearchParams (location.search) const tagsQuery = query.get ('tags') ?? '' const anyFlg = query.get ('match') === 'any' const match = anyFlg ? 'any' : 'all' const tags = useMemo (() => tagsQuery.split (' ').filter (e => e !== ''), [tagsQuery]) const tagsKey = tags.join (' ') const page = Number (query.get ('page') ?? 1) const limit = ( parseLimit (query.get ('limit')) ?? (hydrated ? getClientListLimit ('postList') : null) ?? DEFAULT_POST_LIST_LIMIT ) const order = 'original_created_at:desc' as const const keys = { tags: tagsKey, match, page, limit, ...(query.has ('tag_refs') && { tagReferences: new URLSearchParams (queryRecordParams (query, 'tag_refs')).toString () }), url: '', title: '', originalCreatedFrom: '', originalCreatedTo: '', createdFrom: '', createdTo: '', updatedFrom: '', updatedTo: '', order } as const const { data, isLoading: loading } = useQuery ({ queryKey: postsKeys.index (keys, locale), queryFn: () => fetchPosts (keys, locale) }) const posts = data?.posts ?? [] const cursor = '' const totalPages = data ? Math.ceil (data.count / limit) : 0 useEffect (() => { if (!hydrated) return setClientListSettings ('postList', { limit }) }, [hydrated, limit]) const updatePage = (nextPage: number) => { const params = new URLSearchParams (location.search) params.set ('page', String (Math.max (1, nextPage))) navigate (`${ location.pathname }?${ params.toString () }`) } const updateListQuery = (next: { limit?: 20 | 50 | 100 }) => { const params = new URLSearchParams (location.search) params.set ('limit', String (next.limit ?? limit)) params.set ('page', '1') navigate (`${ location.pathname }?${ params.toString () }`) } useKeyboardShortcuts (useMemo (() => ({ ...(page > 1 ? { 'pagination.previous': () => { updatePage (page - 1) }, } : { }), ...(totalPages > 0 && page < totalPages ? { 'pagination.next': () => { updatePage (Math.min (page + 1, totalPages)) }, } : { }) }), [page, totalPages, location.search])) useLayoutEffect (() => { scroll (0, 0) setWikiPage (null) if (tags.length !== 1) return void (async () => { try { const tagName = tags[0] setWikiPage (await fetchWikiPageByTitle (tagName, { }, locale)) } catch { ; } }) () }, [location.search, tags, locale]) return (
0}/> { const statesToSave = { posts, cursor, scroll: containerRef.current?.scrollTop ?? 0 } sessionStorage.setItem (`posts:${ tagsQuery }`, JSON.stringify (statesToSave)) }}/> {label ('common:countLabel')} }> {posts.length > 0 ? ( <> ) : !(loading) && label ('list.empty')} {loading && label ('common:loading')} {tags.length === 1 && (
{label ('list.viewWiki')}
)}
) } export default PostListPage