From 3e5eb4687b3dd7df08614c3d4dc750a69912b5cb Mon Sep 17 00:00:00 2001 From: miteruzo Date: Wed, 25 Feb 2026 00:56:37 +0900 Subject: [PATCH] #206 --- frontend/src/lib/posts.ts | 30 +++-- frontend/src/lib/queryKeys.ts | 14 +- frontend/src/pages/posts/PostListPage.tsx | 2 +- frontend/src/pages/posts/PostSearchPage.tsx | 136 +++++++++++++++----- frontend/src/types.ts | 5 +- 5 files changed, 135 insertions(+), 52 deletions(-) diff --git a/frontend/src/lib/posts.ts b/frontend/src/lib/posts.ts index 99c95f3..181945e 100644 --- a/frontend/src/lib/posts.ts +++ b/frontend/src/lib/posts.ts @@ -4,22 +4,28 @@ import type { Post, PostTagChange } from '@/types' export const fetchPosts = async ( - { tags, match, page, limit, cursor }: { - tags: string - match: 'any' | 'all' - page?: number - limit?: number - cursor?: string } + { url, title, tags, match, created_from, created_to, updated_from, + updated_to, original_created_from, original_created_to, page, limit }: { + url?: string + title?: string + tags?: string + match?: 'all' | 'any' + created_from?: string + created_to?: string + updated_from?: string + updated_to?: string + original_created_from?: string + original_created_to?: string + page?: number + limit?: number }, ): Promise<{ posts: Post[] - count: number - nextCursor: string }> => + count: number }> => await apiGet ('/posts', { params: { - tags, - match, + url, title, tags, match, created_from, created_to, updated_from, updated_to, + original_created_from, original_created_to, ...(page && { page }), - ...(limit && { limit }), - ...(cursor && { cursor }) } }) + ...(limit && { limit }) } }) export const fetchPost = async (id: string): Promise => await apiGet (`/posts/${ id }`) diff --git a/frontend/src/lib/queryKeys.ts b/frontend/src/lib/queryKeys.ts index 909d54e..081afea 100644 --- a/frontend/src/lib/queryKeys.ts +++ b/frontend/src/lib/queryKeys.ts @@ -1,7 +1,17 @@ export const postsKeys = { root: ['posts'] as const, - index: (p: { tags: string; match: 'any' | 'all'; page: number; limit: number }) => - ['posts', 'index', p] as const, + index: (p: { url?: string + title?: string + tags?: string + match?: 'all' | 'any' + created_from?: string + created_to?: string + updated_from?: string + updated_to?: string + original_created_from?: string + original_created_to?: string + page?: number + limit?: number }) => ['posts', 'index', p] as const, show: (id: string) => ['posts', id] as const, related: (id: string) => ['related', id] as const, changes: (p: { id?: string; page: number; limit: number }) => diff --git a/frontend/src/pages/posts/PostListPage.tsx b/frontend/src/pages/posts/PostListPage.tsx index 8dc20d6..95eca92 100644 --- a/frontend/src/pages/posts/PostListPage.tsx +++ b/frontend/src/pages/posts/PostListPage.tsx @@ -39,7 +39,7 @@ export default (() => { queryKey: postsKeys.index ({ tags: tagsKey, match, page, limit }), queryFn: () => fetchPosts ({ tags: tagsKey, match, page, limit }) }) const posts = data?.posts ?? [] - const cursor = data?.nextCursor ?? '' + const cursor = '' const totalPages = data ? Math.ceil (data.count / limit) : 0 useLayoutEffect (() => { diff --git a/frontend/src/pages/posts/PostSearchPage.tsx b/frontend/src/pages/posts/PostSearchPage.tsx index cb5067e..a03e834 100644 --- a/frontend/src/pages/posts/PostSearchPage.tsx +++ b/frontend/src/pages/posts/PostSearchPage.tsx @@ -2,12 +2,15 @@ import { useState } from 'react' import { Helmet } from 'react-helmet-async' import { useLocation } from 'react-router-dom' +import PrefetchLink from '@/components/PrefetchLink' +import TagLink from '@/components/TagLink' import DateTimeField from '@/components/common/DateTimeField' import Label from '@/components/common/Label' -import SectionTitle from '@/components/common/SectionTitle' +import PageTitle from '@/components/common/PageTitle' +import Pagination from '@/components/common/Pagination' import MainArea from '@/components/layout/MainArea' import { SITE_TITLE } from '@/config' -import { apiGet } from '@/lib/api' +import { fetchPosts } from '@/lib/posts' import type { FC, FormEvent } from 'react' @@ -15,17 +18,18 @@ import type { Post } from '@/types' export default (() => { - const [createdFrom, setCreatedFrom] = useState (null) - const [createdTo, setCreatedTo] = useState (null) + const [createdFrom, setCreatedFrom] = useState () + const [createdTo, setCreatedTo] = useState () const [matchType, setMatchType] = useState<'all' | 'any'> ('all') - const [originalCreatedFrom, setOriginalCreatedFrom] = useState (null) - const [originalCreatedTo, setOriginalCreatedTo] = useState (null) + const [originalCreatedFrom, setOriginalCreatedFrom] = useState () + const [originalCreatedTo, setOriginalCreatedTo] = useState () const [tagsStr, setTagsStr] = useState ('') const [title, setTitle] = useState ('') - const [updatedFrom, setUpdatedFrom] = useState (null) - const [updatedTo, setUpdatedTo] = useState (null) + const [updatedFrom, setUpdatedFrom] = useState () + const [updatedTo, setUpdatedTo] = useState () const [url, setURL] = useState ('') const [results, setResults] = useState ([]) + const [totalPages, setTotalPages] = useState (0) const location = useLocation () const query = new URLSearchParams (location.search) @@ -34,13 +38,15 @@ export default (() => { const search = async () => { const tags = tagsStr.split (' ').filter (e => e !== '') - setResults (await apiGet ('/posts', { params: { + 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 } })) + page, limit }) + setResults (data.posts) + setTotalPages (data ? Math.ceil (data.count / limit) : 0) } const handleSearch = (e: FormEvent) => { @@ -55,18 +61,9 @@ export default (() => {
- 広場検索 -
- {/* URL */} -
- - setURL (e.target.value)} - className="w-full border p-2 rounded"/> -
+ 広場検索 + {/* タイトル */}
@@ -77,6 +74,16 @@ export default (() => { className="w-full border p-2 rounded"/>
+ {/* URL */} +
+ + setURL (e.target.value)} + className="w-full border p-2 rounded"/> +
+ {/* タグ */}
@@ -111,11 +118,11 @@ export default (() => { + onChange={isoUTC => setCreatedFrom (isoUTC ?? undefined)}/> + onChange={isoUTC => setCreatedTo (isoUTC ?? undefined)}/>
{/* 更新日時 */} @@ -123,11 +130,11 @@ export default (() => { + onChange={isoUTC => setUpdatedFrom (isoUTC ?? undefined)}/> + onChange={isoUTC => setUpdatedTo (isoUTC ?? undefined)}/>
{/* オリジナルの投稿日時 */} @@ -135,11 +142,11 @@ export default (() => { + onChange={isoUTC => setOriginalCreatedFrom (isoUTC ?? undefined)}/> + onChange={isoUTC => setOriginalCreatedTo (isoUTC ?? undefined)}/> {/* 検索 */} @@ -153,13 +160,72 @@ export default (() => { -
- - - - - -
-
+ {results.length > 0 && ( +
+
+ + + + + + + + + + + + + + + + + + + + + + + + {results.map (row => ( + + + + + + + + + ))} + +
投稿タイトルURLタグオリジナルの投稿日時投稿日時更新日時
+ + {row.title + + + + {row.title} + + + + {row.url} + + + {row.tags.map (t => ( + + + ))} + + {row.originalCreatedFrom} 〜 {row.originalCreatedBefore} + {row.createdAt}{row.updatedAt}
+
+ + +
)} ) }) satisfies FC diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 5cf9f5d..156f785 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -25,9 +25,10 @@ export type Post = { tags: Tag[] viewed: boolean related: Post[] - createdAt: string originalCreatedFrom: string | null - originalCreatedBefore: string | null } + originalCreatedBefore: string | null + createdAt: string + updatedAt: string } export type PostTagChange = { post: Post