| @@ -3,13 +3,23 @@ import type { Category } from 'types' | |||||
| export const LIGHT_COLOUR_SHADE = 800 | export const LIGHT_COLOUR_SHADE = 800 | ||||
| export const DARK_COLOUR_SHADE = 300 | export const DARK_COLOUR_SHADE = 300 | ||||
| export const CATEGORIES = ['deerjikist', | |||||
| 'meme', | |||||
| 'character', | |||||
| 'general', | |||||
| 'material', | |||||
| 'meta', | |||||
| 'nico'] as const | |||||
| export const CATEGORIES = [ | |||||
| 'deerjikist', | |||||
| 'meme', | |||||
| 'character', | |||||
| 'general', | |||||
| 'material', | |||||
| 'meta', | |||||
| 'nico', | |||||
| ] as const | |||||
| export const FETCH_POSTS_ORDER_FIELDS = [ | |||||
| 'title', | |||||
| 'url', | |||||
| 'original_created_at', | |||||
| 'created_at', | |||||
| 'updated_at', | |||||
| ] as const | |||||
| export const TAG_COLOUR = { | export const TAG_COLOUR = { | ||||
| deerjikist: 'rose', | deerjikist: 'rose', | ||||
| @@ -18,10 +28,13 @@ export const TAG_COLOUR = { | |||||
| general: 'cyan', | general: 'cyan', | ||||
| material: 'orange', | material: 'orange', | ||||
| meta: 'yellow', | meta: 'yellow', | ||||
| nico: 'gray' } as const satisfies Record<Category, string> | |||||
| nico: 'gray', | |||||
| } as const satisfies Record<Category, string> | |||||
| export const USER_ROLES = ['admin', 'member', 'guest'] as const | export const USER_ROLES = ['admin', 'member', 'guest'] as const | ||||
| export const ViewFlagBehavior = { OnShowedDetail: 1, | |||||
| OnClickedLink: 2, | |||||
| NotAuto: 3 } as const | |||||
| export const ViewFlagBehavior = { | |||||
| OnShowedDetail: 1, | |||||
| OnClickedLink: 2, | |||||
| NotAuto: 3, | |||||
| } as const | |||||
| @@ -1,31 +1,28 @@ | |||||
| import { apiDelete, apiGet, apiPost } from '@/lib/api' | import { apiDelete, apiGet, apiPost } from '@/lib/api' | ||||
| import type { Post, PostTagChange } from '@/types' | |||||
| import type { FetchPostsParams, Post, PostTagChange } from '@/types' | |||||
| export const fetchPosts = async ( | export const fetchPosts = async ( | ||||
| { 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 }, | |||||
| { url, title, tags, match, createdFrom, createdTo, updatedFrom, updatedTo, | |||||
| originalCreatedFrom, originalCreatedTo, page, limit, order }: FetchPostsParams | |||||
| ): Promise<{ | ): Promise<{ | ||||
| posts: Post[] | |||||
| count: number }> => | |||||
| posts: Post[] | |||||
| count: number }> => | |||||
| await apiGet ('/posts', { params: { | await apiGet ('/posts', { params: { | ||||
| url, title, tags, match, created_from, created_to, updated_from, updated_to, | |||||
| original_created_from, original_created_to, | |||||
| ...(url && { url }), | |||||
| ...(title && { title }), | |||||
| ...(tags && { tags }), | |||||
| ...(match && { match }), | |||||
| ...(createdFrom && { created_from: createdFrom }), | |||||
| ...(createdTo && { created_to: createdTo }), | |||||
| ...(updatedFrom && { updated_from: updatedFrom }), | |||||
| ...(updatedTo && { updated_to: updatedTo }), | |||||
| ...(originalCreatedFrom && { original_created_from: originalCreatedFrom }), | |||||
| ...(originalCreatedTo && { original_created_to: originalCreatedTo }), | |||||
| ...(page && { page }), | ...(page && { page }), | ||||
| ...(limit && { limit }) } }) | |||||
| ...(limit && { limit }), | |||||
| ...(order && { order }) } }) | |||||
| export const fetchPost = async (id: string): Promise<Post> => await apiGet (`/posts/${ id }`) | export const fetchPost = async (id: string): Promise<Post> => await apiGet (`/posts/${ id }`) | ||||
| @@ -1,17 +1,8 @@ | |||||
| import type { FetchPostsParams } from '@/types' | |||||
| export const postsKeys = { | export const postsKeys = { | ||||
| root: ['posts'] as const, | root: ['posts'] 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, | |||||
| index: (p: FetchPostsParams) => ['posts', 'index', p] as const, | |||||
| show: (id: string) => ['posts', id] as const, | show: (id: string) => ['posts', id] as const, | ||||
| related: (id: string) => ['related', id] as const, | related: (id: string) => ['related', id] as const, | ||||
| changes: (p: { id?: string; page: number; limit: number }) => | changes: (p: { id?: string; page: number; limit: number }) => | ||||
| @@ -18,7 +18,7 @@ import { postsKeys } from '@/lib/queryKeys' | |||||
| import type { FC, ChangeEvent, FormEvent, KeyboardEvent } from 'react' | import type { FC, ChangeEvent, FormEvent, KeyboardEvent } from 'react' | ||||
| import type { Tag } from '@/types' | |||||
| import type { FetchPostsOrder, FetchPostsParams, Tag } from '@/types' | |||||
| const setIf = (qs: URLSearchParams, k: string, v: string | null) => { | const setIf = (qs: URLSearchParams, k: string, v: string | null) => { | ||||
| @@ -49,11 +49,13 @@ export default (() => { | |||||
| const qCreatedTo = query.get ('created_to') | const qCreatedTo = query.get ('created_to') | ||||
| const qUpdatedFrom = query.get ('updated_from') | const qUpdatedFrom = query.get ('updated_from') | ||||
| const qUpdatedTo = query.get ('updated_to') | const qUpdatedTo = query.get ('updated_to') | ||||
| const qOrder = (query.get ('order') || 'original_created_at:desc') as FetchPostsOrder | |||||
| const [activeIndex, setActiveIndex] = useState (-1) | const [activeIndex, setActiveIndex] = useState (-1) | ||||
| const [createdFrom, setCreatedFrom] = useState (qCreatedFrom) | const [createdFrom, setCreatedFrom] = useState (qCreatedFrom) | ||||
| const [createdTo, setCreatedTo] = useState (qCreatedTo) | const [createdTo, setCreatedTo] = useState (qCreatedTo) | ||||
| const [matchType, setMatchType] = useState (qMatch ?? 'all') | const [matchType, setMatchType] = useState (qMatch ?? 'all') | ||||
| const [order, setOrder] = useState<FetchPostsOrder> ('original_created_at:desc') | |||||
| const [originalCreatedFrom, setOriginalCreatedFrom] = useState (qOriginalCreatedFrom) | const [originalCreatedFrom, setOriginalCreatedFrom] = useState (qOriginalCreatedFrom) | ||||
| const [originalCreatedTo, setOriginalCreatedTo] = useState (qOriginalCreatedTo) | const [originalCreatedTo, setOriginalCreatedTo] = useState (qOriginalCreatedTo) | ||||
| const [suggestions, setSuggestions] = useState<Tag[]> ([]) | const [suggestions, setSuggestions] = useState<Tag[]> ([]) | ||||
| @@ -64,16 +66,17 @@ export default (() => { | |||||
| const [updatedTo, setUpdatedTo] = useState (qUpdatedTo) | const [updatedTo, setUpdatedTo] = useState (qUpdatedTo) | ||||
| const [url, setURL] = useState (qURL ?? '') | const [url, setURL] = useState (qURL ?? '') | ||||
| const keys = { | |||||
| const keys: FetchPostsParams = { | |||||
| tags: qTags, match: qMatch, page, limit, | tags: qTags, match: qMatch, page, limit, | ||||
| ...(qURL && { url: qURL }), | ...(qURL && { url: qURL }), | ||||
| ...(qTitle && { title: qTitle }), | ...(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 }) } | |||||
| ...(qOriginalCreatedFrom && { originalCreatedFrom: qOriginalCreatedFrom }), | |||||
| ...(qOriginalCreatedTo && { originalCreatedTo: qOriginalCreatedTo }), | |||||
| ...(qCreatedFrom && { createdFrom: qCreatedFrom }), | |||||
| ...(qCreatedTo && { createdTo: qCreatedTo }), | |||||
| ...(qUpdatedFrom && { updatedFrom: qUpdatedFrom }), | |||||
| ...(qUpdatedTo && { updatedTo: qUpdatedTo }), | |||||
| ...(qOrder && { order: qOrder }) } | |||||
| const { data, isLoading: loading } = useQuery ({ | const { data, isLoading: loading } = useQuery ({ | ||||
| queryKey: postsKeys.index (keys), | queryKey: postsKeys.index (keys), | ||||
| queryFn: () => fetchPosts (keys) }) | queryFn: () => fetchPosts (keys) }) | ||||
| @@ -91,6 +94,7 @@ export default (() => { | |||||
| setCreatedTo (qCreatedTo) | setCreatedTo (qCreatedTo) | ||||
| setUpdatedFrom (qUpdatedFrom) | setUpdatedFrom (qUpdatedFrom) | ||||
| setUpdatedTo (qUpdatedTo) | setUpdatedTo (qUpdatedTo) | ||||
| setOrder (qOrder) | |||||
| document.querySelector ('table')?.scrollIntoView ({ behavior: 'smooth' }) | document.querySelector ('table')?.scrollIntoView ({ behavior: 'smooth' }) | ||||
| }, [location.search]) | }, [location.search]) | ||||
| @@ -160,6 +164,7 @@ export default (() => { | |||||
| setIf (qs, 'updated_to', updatedTo) | setIf (qs, 'updated_to', updatedTo) | ||||
| qs.set ('match', matchType) | qs.set ('match', matchType) | ||||
| qs.set ('page', String ('1')) | qs.set ('page', String ('1')) | ||||
| qs.set ('order', order) | |||||
| navigate (`${ location.pathname }?${ qs.toString () }`) | navigate (`${ location.pathname }?${ qs.toString () }`) | ||||
| } | } | ||||
| @@ -1,9 +1,31 @@ | |||||
| import { CATEGORIES, USER_ROLES, ViewFlagBehavior } from '@/consts' | |||||
| import { CATEGORIES, | |||||
| FETCH_POSTS_ORDER_FIELDS, | |||||
| USER_ROLES, | |||||
| ViewFlagBehavior } from '@/consts' | |||||
| import type { ReactNode } from 'react' | import type { ReactNode } from 'react' | ||||
| export type Category = typeof CATEGORIES[number] | export type Category = typeof CATEGORIES[number] | ||||
| export type FetchPostsOrder = `${ FetchPostsOrderField }:${ 'asc' | 'desc' }` | |||||
| export type FetchPostsOrderField = typeof FETCH_POSTS_ORDER_FIELDS[number] | |||||
| export type FetchPostsParams = { | |||||
| url?: string | |||||
| title?: string | |||||
| tags?: string | |||||
| match?: 'all' | 'any' | |||||
| createdFrom?: string | |||||
| createdTo?: string | |||||
| updatedFrom?: string | |||||
| updatedTo?: string | |||||
| originalCreatedFrom?: string | |||||
| originalCreatedTo?: string | |||||
| page?: number | |||||
| limit?: number | |||||
| order?: FetchPostsOrder } | |||||
| export type Menu = MenuItem[] | export type Menu = MenuItem[] | ||||
| export type MenuItem = { | export type MenuItem = { | ||||