|
|
|
@@ -18,7 +18,10 @@ import { postsKeys } from '@/lib/queryKeys' |
|
|
|
|
|
|
|
import type { FC, ChangeEvent, FormEvent, KeyboardEvent } from 'react' |
|
|
|
|
|
|
|
import type { FetchPostsOrder, FetchPostsParams, Tag } from '@/types' |
|
|
|
import type { FetchPostsOrder, |
|
|
|
FetchPostsOrderField, |
|
|
|
FetchPostsParams, |
|
|
|
Tag } from '@/types' |
|
|
|
|
|
|
|
|
|
|
|
const setIf = (qs: URLSearchParams, k: string, v: string | null) => { |
|
|
|
@@ -49,13 +52,12 @@ export default (() => { |
|
|
|
const qCreatedTo = query.get ('created_to') |
|
|
|
const qUpdatedFrom = query.get ('updated_from') |
|
|
|
const qUpdatedTo = query.get ('updated_to') |
|
|
|
const qOrder = (query.get ('order') || 'original_created_at:desc') as FetchPostsOrder |
|
|
|
const order = (query.get ('order') || 'original_created_at:desc') as FetchPostsOrder |
|
|
|
|
|
|
|
const [activeIndex, setActiveIndex] = useState (-1) |
|
|
|
const [createdFrom, setCreatedFrom] = useState (qCreatedFrom) |
|
|
|
const [createdTo, setCreatedTo] = useState (qCreatedTo) |
|
|
|
const [matchType, setMatchType] = useState (qMatch ?? 'all') |
|
|
|
const [order, setOrder] = useState<FetchPostsOrder> ('original_created_at:desc') |
|
|
|
const [originalCreatedFrom, setOriginalCreatedFrom] = useState (qOriginalCreatedFrom) |
|
|
|
const [originalCreatedTo, setOriginalCreatedTo] = useState (qOriginalCreatedTo) |
|
|
|
const [suggestions, setSuggestions] = useState<Tag[]> ([]) |
|
|
|
@@ -76,7 +78,7 @@ export default (() => { |
|
|
|
...(qCreatedTo && { createdTo: qCreatedTo }), |
|
|
|
...(qUpdatedFrom && { updatedFrom: qUpdatedFrom }), |
|
|
|
...(qUpdatedTo && { updatedTo: qUpdatedTo }), |
|
|
|
...(qOrder && { order: qOrder }) } |
|
|
|
...(order && { order }) } |
|
|
|
const { data, isLoading: loading } = useQuery ({ |
|
|
|
queryKey: postsKeys.index (keys), |
|
|
|
queryFn: () => fetchPosts (keys) }) |
|
|
|
@@ -94,11 +96,32 @@ export default (() => { |
|
|
|
setCreatedTo (qCreatedTo) |
|
|
|
setUpdatedFrom (qUpdatedFrom) |
|
|
|
setUpdatedTo (qUpdatedTo) |
|
|
|
setOrder (qOrder) |
|
|
|
|
|
|
|
document.querySelector ('table')?.scrollIntoView ({ behavior: 'smooth' }) |
|
|
|
}, [location.search]) |
|
|
|
|
|
|
|
const SortHeader = ({ by, label }: { by: FetchPostsOrderField; label: string }) => { |
|
|
|
const [fld, dir] = order.split (':') |
|
|
|
|
|
|
|
const qs = new URLSearchParams (location.search) |
|
|
|
const nextDir = |
|
|
|
(by === fld) |
|
|
|
? (dir === 'asc' ? 'desc' : 'asc') |
|
|
|
: (['title', 'url'].includes (by) ? 'asc' : 'desc') |
|
|
|
qs.set ('order', `${ by }:${ nextDir }`) |
|
|
|
qs.set ('page', '1') |
|
|
|
|
|
|
|
return ( |
|
|
|
<PrefetchLink |
|
|
|
className="text-inherit visited:text-inherit hover:text-inherit" |
|
|
|
to={`${ location.pathname }?${ qs.toString () }`}> |
|
|
|
<span className="font-bold"> |
|
|
|
{label} |
|
|
|
{by === fld && (dir === 'asc' ? ' ▲' : ' ▼')} |
|
|
|
</span> |
|
|
|
</PrefetchLink>) |
|
|
|
} |
|
|
|
|
|
|
|
// TODO: TagSearch からのコピペのため,共通化を考へる. |
|
|
|
const whenChanged = async (ev: ChangeEvent<HTMLInputElement>) => { |
|
|
|
setTagsStr (ev.target.value) |
|
|
|
@@ -305,7 +328,7 @@ export default (() => { |
|
|
|
<col className="w-72"/> |
|
|
|
<col className="w-80"/> |
|
|
|
<col className="w-[24rem]"/> |
|
|
|
<col className="w-44"/> |
|
|
|
<col className="w-60"/> |
|
|
|
<col className="w-44"/> |
|
|
|
<col className="w-44"/> |
|
|
|
</colgroup> |
|
|
|
@@ -313,12 +336,22 @@ export default (() => { |
|
|
|
<thead className="border-b-2 border-black dark:border-white"> |
|
|
|
<tr> |
|
|
|
<th className="p-2 text-left whitespace-nowrap">投稿</th> |
|
|
|
<th className="p-2 text-left whitespace-nowrap">タイトル</th> |
|
|
|
<th className="p-2 text-left whitespace-nowrap">URL</th> |
|
|
|
<th className="p-2 text-left whitespace-nowrap"> |
|
|
|
<SortHeader by="title" label="タイトル"/> |
|
|
|
</th> |
|
|
|
<th className="p-2 text-left whitespace-nowrap"> |
|
|
|
<SortHeader by="url" label="URL"/> |
|
|
|
</th> |
|
|
|
<th className="p-2 text-left whitespace-nowrap">タグ</th> |
|
|
|
<th className="p-2 text-left whitespace-nowrap">オリジナルの投稿日時</th> |
|
|
|
<th className="p-2 text-left whitespace-nowrap">投稿日時</th> |
|
|
|
<th className="p-2 text-left whitespace-nowrap">更新日時</th> |
|
|
|
<th className="p-2 text-left whitespace-nowrap"> |
|
|
|
<SortHeader by="original_created_at" label="オリジナルの投稿日時"/> |
|
|
|
</th> |
|
|
|
<th className="p-2 text-left whitespace-nowrap"> |
|
|
|
<SortHeader by="created_at" label="投稿日時"/> |
|
|
|
</th> |
|
|
|
<th className="p-2 text-left whitespace-nowrap"> |
|
|
|
<SortHeader by="updated_at" label="更新日時"/> |
|
|
|
</th> |
|
|
|
</tr> |
|
|
|
</thead> |
|
|
|
<tbody> |
|
|
|
|