| @@ -1,5 +1,5 @@ | |||
| import { useQuery } from '@tanstack/react-query' | |||
| import { useState } from 'react' | |||
| import { useEffect, useMemo, useState } from 'react' | |||
| import { Helmet } from 'react-helmet-async' | |||
| import { useLocation, useNavigate } from 'react-router-dom' | |||
| @@ -17,49 +17,89 @@ import { postsKeys } from '@/lib/queryKeys' | |||
| import type { FC, FormEvent } from 'react' | |||
| 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 location = useLocation () | |||
| const query = new URLSearchParams (location.search) | |||
| const query = useMemo (() => new URLSearchParams (location.search), | |||
| [location.search]) | |||
| const page = Number (query.get ('page') ?? 1) | |||
| 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 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 [createdFrom, setCreatedFrom] = useState (qCreatedFrom) | |||
| const [createdTo, setCreatedTo] = useState (qCreatedTo) | |||
| const [matchType, setMatchType] = useState (qMatch ?? 'all') | |||
| const [originalCreatedFrom, setOriginalCreatedFrom] = useState (qOriginalCreatedFrom) | |||
| const [originalCreatedTo, setOriginalCreatedTo] = useState (qOriginalCreatedTo) | |||
| const [tagsStr, setTagsStr] = useState (qTags) | |||
| const [title, setTitle] = useState (qTitle ?? '') | |||
| const [updatedFrom, setUpdatedFrom] = useState (qUpdatedFrom) | |||
| const [updatedTo, setUpdatedTo] = useState (qUpdatedTo) | |||
| const [url, setURL] = useState (qURL ?? '') | |||
| 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) }) | |||
| tags: qTags, match: qMatch, page, limit, | |||
| ...(qURL && { url: qURL }), | |||
| ...(qTitle && { title: qTitle }), | |||
| ...(qOriginalCreatedFrom && { original_created_from: qOriginalCreatedFrom }), | |||
| ...(qOriginalCreatedTo && { original_created_to: qOriginalCreatedTo }), | |||
| ...(qCreatedFrom && { created_from: qCreatedFrom }), | |||
| ...(qCreatedTo && { created_to: qCreatedTo }), | |||
| ...(qUpdatedFrom && { updated_from: qUpdatedFrom }), | |||
| ...(qUpdatedTo && { updated_to: qUpdatedTo }) } | |||
| 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.getElementsByTagName ('main')![0].scroll (0, 0) | |||
| }, [location.search]) | |||
| const search = async () => { | |||
| const qs = new URLSearchParams (location.search) | |||
| 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', String ('1')) | |||
| navigate (`${ location.pathname }?${ qs.toString () }`) | |||
| } | |||
| @@ -175,7 +215,7 @@ export default (() => { | |||
| </form> | |||
| </div> | |||
| {results.length > 0 && ( | |||
| {loading ? 'Loading...' : (results.length > 0 ? ( | |||
| <div className="mt-4"> | |||
| <div className="overflow-x-auto"> | |||
| <table className="w-full min-w-[1200px] table-fixed border-collapse"> | |||
| @@ -241,6 +281,6 @@ export default (() => { | |||
| </div> | |||
| <Pagination page={page} totalPages={totalPages}/> | |||
| </div>)} | |||
| </div>) : '結果ないよ(笑)')} | |||
| </MainArea>) | |||
| }) satisfies FC | |||