import { useQuery } from '@tanstack/react-query' import { motion } from 'framer-motion' import { useEffect, useMemo, useState } from 'react' import { Helmet } from 'react-helmet-async' import { useLocation, useNavigate } from 'react-router-dom' import PrefetchLink from '@/components/PrefetchLink' import SortHeader from '@/components/SortHeader' import TagLink from '@/components/TagLink' import DateTimeField from '@/components/common/DateTimeField' import Label from '@/components/common/Label' import PageTitle from '@/components/common/PageTitle' import Pagination from '@/components/common/Pagination' import TagInput from '@/components/common/TagInput' import MainArea from '@/components/layout/MainArea' import { SITE_TITLE } from '@/config' import { fetchPosts } from '@/lib/posts' import { postsKeys } from '@/lib/queryKeys' import { dateString, originalCreatedAtString } from '@/lib/utils' import type { FC, FormEvent } from 'react' import type { FetchPostsOrder, FetchPostsOrderField, FetchPostsParams } from '@/types' const setIf = (qs: URLSearchParams, k: string, v: string | null) => { const t = v?.trim () if (t) qs.set (k, t) } export default (() => { const location = useLocation () const navigate = useNavigate () const query = useMemo (() => new URLSearchParams (location.search), [location.search]) const page = Number (query.get ('page') ?? 1) const limit = Number (query.get ('limit') ?? 20) const qURL = query.get ('url') ?? '' const qTitle = query.get ('title') ?? '' const qTags = query.get ('tags') ?? '' const qMatch: 'all' | 'any' = query.get ('match') === 'any' ? 'any' : 'all' const qOriginalCreatedFrom = query.get ('original_created_from') ?? '' const qOriginalCreatedTo = query.get ('original_created_to') ?? '' const qCreatedFrom = query.get ('created_from') ?? '' const qCreatedTo = query.get ('created_to') ?? '' const qUpdatedFrom = query.get ('updated_from') ?? '' const qUpdatedTo = query.get ('updated_to') ?? '' const order = (query.get ('order') || 'original_created_at:desc') as FetchPostsOrder const [createdFrom, setCreatedFrom] = useState (null) const [createdTo, setCreatedTo] = useState (null) const [matchType, setMatchType] = useState<'all' | 'any'> ('all') const [originalCreatedFrom, setOriginalCreatedFrom] = useState (null) const [originalCreatedTo, setOriginalCreatedTo] = useState (null) const [tagsStr, setTagsStr] = useState ('') const [title, setTitle] = useState ('') const [updatedFrom, setUpdatedFrom] = useState (null) const [updatedTo, setUpdatedTo] = useState (null) const [url, setURL] = useState ('') const keys: FetchPostsParams = { tags: qTags, match: qMatch, page, limit, url: qURL, title: qTitle, originalCreatedFrom: qOriginalCreatedFrom, originalCreatedTo: qOriginalCreatedTo, createdFrom: qCreatedFrom, createdTo: qCreatedTo, updatedFrom: qUpdatedFrom, updatedTo: qUpdatedTo, order } const { data, isLoading: loading } = useQuery ({ queryKey: postsKeys.index (keys), queryFn: () => fetchPosts (keys) }) const results = data?.posts ?? [] const totalPages = data ? Math.ceil (data.count / limit) : 0 useEffect (() => { setURL (qURL ?? '') setTitle (qTitle ?? '') setTagsStr (qTags ?? '') setMatchType (qMatch ?? 'all') setOriginalCreatedFrom (qOriginalCreatedFrom) setOriginalCreatedTo (qOriginalCreatedTo) setCreatedFrom (qCreatedFrom) setCreatedTo (qCreatedTo) setUpdatedFrom (qUpdatedFrom) setUpdatedTo (qUpdatedTo) document.querySelector ('table')?.scrollIntoView ({ behavior: 'smooth' }) }, [location.search]) const search = async () => { const qs = new URLSearchParams () setIf (qs, 'tags', tagsStr) setIf (qs, 'url', url) setIf (qs, 'title', title) setIf (qs, 'original_created_from', originalCreatedFrom) setIf (qs, 'original_created_to', originalCreatedTo) setIf (qs, 'created_from', createdFrom) setIf (qs, 'created_to', createdTo) setIf (qs, 'updated_from', updatedFrom) setIf (qs, 'updated_to', updatedTo) qs.set ('match', matchType) qs.set ('page', '1') qs.set ('order', order) navigate (`${ location.pathname }?${ qs.toString () }`) } const handleSearch = (e: FormEvent) => { e.preventDefault () search () } const defaultDirection = { title: 'asc', url: 'asc', original_created_at: 'desc', created_at: 'desc', updated_at: 'desc' } as const return ( 広場検索 | {SITE_TITLE}
広場検索
{/* タイトル */}
setTitle (e.target.value)} className="w-full border p-2 rounded"/>
{/* URL */}
setURL (e.target.value)} className="w-full border p-2 rounded"/>
{/* タグ */}
{/* オリジナルの投稿日時 */}
{/* 投稿日時 */}
{/* 更新日時 */}
{/* 検索 */}
{loading ? 'Loading...' : (results.length > 0 ? (
{results.map (row => ( ))}
投稿 by="title" label="タイトル" currentOrder={order} defaultDirection={defaultDirection}/> by="url" label="URL" currentOrder={order} defaultDirection={defaultDirection}/> タグ by="original_created_at" label="オリジナルの投稿日時" currentOrder={order} defaultDirection={defaultDirection}/> by="created_at" label="投稿日時" currentOrder={order} defaultDirection={defaultDirection}/> by="updated_at" label="更新日時" currentOrder={order} defaultDirection={defaultDirection}/>
{row.title {row.title} {row.url} {row.tags.map (t => ( ))} {originalCreatedAtString (row.originalCreatedFrom, row.originalCreatedBefore)} {dateString (row.createdAt)} {dateString (row.updatedAt)}
) : '結果ないよ(笑)')}
) }) satisfies FC