Browse Source

#206

feature/206
みてるぞ 1 week ago
parent
commit
c3aa8bc580
2 changed files with 71 additions and 35 deletions
  1. +25
    -4
      frontend/src/lib/prefetchers.ts
  2. +46
    -31
      frontend/src/pages/posts/PostSearchPage.tsx

+ 25
- 4
frontend/src/lib/prefetchers.ts View File

@@ -68,13 +68,32 @@ const prefetchWikiPageShow: Prefetcher = async (qc, url) => {


const prefetchPostsIndex: Prefetcher = async (qc, url) => { const prefetchPostsIndex: Prefetcher = async (qc, url) => {
const tags = url.searchParams.get ('tags') ?? '' const tags = url.searchParams.get ('tags') ?? ''
const m = url.searchParams.get ('match') === 'any' ? 'any' : 'all'
const qURL = url.searchParams.get ('url')
const title = url.searchParams.get ('title')
const originalCreatedFrom = url.searchParams.get ('original_created_from')
const originalCreatedTo = url.searchParams.get ('original_created_to')
const createdFrom = url.searchParams.get ('created_from')
const createdTo = url.searchParams.get ('created_to')
const updatedFrom = url.searchParams.get ('updated_from')
const updatedTo = url.searchParams.get ('updated_to')
const m: 'all' | 'any' = url.searchParams.get ('match') === 'any' ? 'any' : 'all'
const page = Number (url.searchParams.get ('page') || 1) const page = Number (url.searchParams.get ('page') || 1)
const limit = Number (url.searchParams.get ('limit') || 20) const limit = Number (url.searchParams.get ('limit') || 20)


const keys = {
tags, match: m, page, limit,
...(qURL && { url: qURL }),
...(title && { title }),
...(originalCreatedFrom && { original_created_from: originalCreatedFrom }),
...(originalCreatedTo && { original_created_to: originalCreatedTo }),
...(createdFrom && { created_from: createdFrom }),
...(createdTo && { created_to: createdTo }),
...(updatedFrom && { updated_from: updatedFrom }),
...(updatedTo && { updated_to: updatedTo }) }

await qc.prefetchQuery ({ await qc.prefetchQuery ({
queryKey: postsKeys.index ({ tags, match: m, page, limit }),
queryFn: () => fetchPosts ({ tags, match: m, page, limit }) })
queryKey: postsKeys.index (keys),
queryFn: () => fetchPosts (keys) })
} }




@@ -103,7 +122,8 @@ const prefetchPostChanges: Prefetcher = async (qc, url) => {




export const routePrefetchers: { test: (u: URL) => boolean; run: Prefetcher }[] = [ export const routePrefetchers: { test: (u: URL) => boolean; run: Prefetcher }[] = [
{ test: u => u.pathname === '/' || u.pathname === '/posts', run: prefetchPostsIndex },
{ test: u => ['/', '/posts', '/posts/search'].includes (u.pathname),
run: prefetchPostsIndex },
{ test: u => (!(['/posts/new', '/posts/changes', '/posts/search'].includes (u.pathname)) { test: u => (!(['/posts/new', '/posts/changes', '/posts/search'].includes (u.pathname))
&& Boolean (mPost (u.pathname))), && Boolean (mPost (u.pathname))),
run: prefetchPostShow }, run: prefetchPostShow },
@@ -119,5 +139,6 @@ export const prefetchForURL = async (qc: QueryClient, urlLike: string): Promise<
const r = routePrefetchers.find (x => x.test (u)) const r = routePrefetchers.find (x => x.test (u))
if (!(r)) if (!(r))
return return

await r.run (qc, u) await r.run (qc, u)
} }

+ 46
- 31
frontend/src/pages/posts/PostSearchPage.tsx View File

@@ -1,6 +1,7 @@
import { useQuery } from '@tanstack/react-query'
import { useState } from 'react' import { useState } from 'react'
import { Helmet } from 'react-helmet-async' import { Helmet } from 'react-helmet-async'
import { useLocation } from 'react-router-dom'
import { useLocation, useNavigate } from 'react-router-dom'


import PrefetchLink from '@/components/PrefetchLink' import PrefetchLink from '@/components/PrefetchLink'
import TagLink from '@/components/TagLink' import TagLink from '@/components/TagLink'
@@ -11,42 +12,56 @@ import Pagination from '@/components/common/Pagination'
import MainArea from '@/components/layout/MainArea' import MainArea from '@/components/layout/MainArea'
import { SITE_TITLE } from '@/config' import { SITE_TITLE } from '@/config'
import { fetchPosts } from '@/lib/posts' import { fetchPosts } from '@/lib/posts'
import { postsKeys } from '@/lib/queryKeys'


import type { FC, FormEvent } from 'react' import type { FC, FormEvent } from 'react'


import type { Post } from '@/types'



export default (() => { export default (() => {
const [createdFrom, setCreatedFrom] = useState<string | undefined> ()
const [createdTo, setCreatedTo] = useState<string | undefined> ()
const [matchType, setMatchType] = useState<'all' | 'any'> ('all')
const [originalCreatedFrom, setOriginalCreatedFrom] = useState<string | undefined> ()
const [originalCreatedTo, setOriginalCreatedTo] = useState<string | undefined> ()
const [tagsStr, setTagsStr] = useState ('')
const [title, setTitle] = useState ('')
const [updatedFrom, setUpdatedFrom] = useState<string | undefined> ()
const [updatedTo, setUpdatedTo] = useState<string | undefined> ()
const [url, setURL] = useState ('')
const [results, setResults] = useState<Post[]> ([])
const [totalPages, setTotalPages] = useState (0)
const navigate = useNavigate ()


const location = useLocation () const location = useLocation ()
const query = new URLSearchParams (location.search) const query = new URLSearchParams (location.search)
const page = Number (query.get ('page') ?? 1) const page = Number (query.get ('page') ?? 1)
const limit = Number (query.get ('limit') ?? 20) const limit = Number (query.get ('limit') ?? 20)


const [createdFrom, setCreatedFrom] =
useState<string | null> (query.get ('created_from'))
const [createdTo, setCreatedTo] =
useState<string | null> (query.get ('created_to'))
const [matchType, setMatchType] =
useState<'all' | 'any'> ((query.get ('match') as 'all' | 'any' | null) ?? 'all')
const [originalCreatedFrom, setOriginalCreatedFrom] =
useState<string | null> (query.get ('original_created_from'))
const [originalCreatedTo, setOriginalCreatedTo] =
useState<string | null> (query.get ('original_created_to'))
const [tagsStr, setTagsStr] = useState (query.get ('tags') ?? '')
const [title, setTitle] = useState (query.get ('title') ?? '')
const [updatedFrom, setUpdatedFrom] =
useState<string | null> (query.get ('updated_from'))
const [updatedTo, setUpdatedTo] =
useState<string | null> (query.get ('updated_to'))
const [url, setURL] = useState (query.get ('url') ?? '')

const keys = {
tags: tagsStr, match: matchType, page, limit,
...(url && { url }),
...(title && { title }),
...(originalCreatedFrom && { original_created_from: originalCreatedFrom }),
...(originalCreatedTo && { original_created_to: originalCreatedTo }),
...(createdFrom && { created_from: createdFrom }),
...(createdTo && { created_to: createdTo }),
...(updatedFrom && { updated_from: updatedFrom }),
...(updatedTo && { updated_to: updatedTo }) }
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

const search = async () => { const search = async () => {
const tags = tagsStr.split (' ').filter (e => e !== '')
const data = await fetchPosts ({
url, title, tags: tags.join (' '), match: matchType,
created_from: createdFrom, created_to: createdTo,
updated_from: updatedFrom, updated_to: updatedTo,
original_created_from: originalCreatedFrom,
original_created_to: originalCreatedTo,
page, limit })
setResults (data.posts)
setTotalPages (data ? Math.ceil (data.count / limit) : 0)
const qs = new URLSearchParams (location.search)
qs.set ('page', String ('1'))
navigate (`${ location.pathname }?${ qs.toString () }`)
} }


const handleSearch = (e: FormEvent) => { const handleSearch = (e: FormEvent) => {
@@ -118,11 +133,11 @@ export default (() => {
<Label>オリジナルの投稿日時</Label> <Label>オリジナルの投稿日時</Label>
<DateTimeField <DateTimeField
value={originalCreatedFrom ?? undefined} value={originalCreatedFrom ?? undefined}
onChange={isoUTC => setOriginalCreatedFrom (isoUTC ?? undefined)}/>
onChange={setOriginalCreatedFrom}/>
<span className="mx-1">〜</span> <span className="mx-1">〜</span>
<DateTimeField <DateTimeField
value={originalCreatedTo ?? undefined} value={originalCreatedTo ?? undefined}
onChange={isoUTC => setOriginalCreatedTo (isoUTC ?? undefined)}/>
onChange={setOriginalCreatedTo}/>
</div> </div>


{/* 投稿日時 */} {/* 投稿日時 */}
@@ -130,11 +145,11 @@ export default (() => {
<Label>投稿日時</Label> <Label>投稿日時</Label>
<DateTimeField <DateTimeField
value={createdFrom ?? undefined} value={createdFrom ?? undefined}
onChange={isoUTC => setCreatedFrom (isoUTC ?? undefined)}/>
onChange={setCreatedFrom}/>
<span className="mx-1">〜</span> <span className="mx-1">〜</span>
<DateTimeField <DateTimeField
value={createdTo ?? undefined} value={createdTo ?? undefined}
onChange={isoUTC => setCreatedTo (isoUTC ?? undefined)}/>
onChange={setCreatedTo}/>
</div> </div>


{/* 更新日時 */} {/* 更新日時 */}
@@ -142,11 +157,11 @@ export default (() => {
<Label>更新日時</Label> <Label>更新日時</Label>
<DateTimeField <DateTimeField
value={updatedFrom ?? undefined} value={updatedFrom ?? undefined}
onChange={isoUTC => setUpdatedFrom (isoUTC ?? undefined)}/>
onChange={setUpdatedFrom}/>
<span className="mx-1">〜</span> <span className="mx-1">〜</span>
<DateTimeField <DateTimeField
value={updatedTo ?? undefined} value={updatedTo ?? undefined}
onChange={isoUTC => setUpdatedTo (isoUTC ?? undefined)}/>
onChange={setUpdatedTo}/>
</div> </div>


{/* 検索 */} {/* 検索 */}


Loading…
Cancel
Save