fedisearch/application/src/components/node/NodeSearch.tsx

161 wiersze
4.6 KiB
TypeScript

'use client'
import { useQuery } from '@apollo/client'
import { usePathname, useRouter, useSearchParams } from 'next/navigation'
import React, { ReactElement, useEffect, useState } from 'react'
import { z } from 'zod'
import {
FeedQueryInput,
ListNodesDocument,
NodeQueryInput,
NodeSortingByEnum,
SortingWayEnum
} from '../../graphql/generated/types'
import { useMatomo } from '../../hooks/MatomoHook'
import createUrlSearchParams from '../../utils/createUrlSearchParams'
import { stringTrimmed, transform } from '../../utils/transform'
import createSortingInputSchema from '../../schema/createSortingInputSchema'
import ErrorMessage from '../ErrorMessage'
import Loader from '../Loader'
import LoadMoreButton from '../LoadMoreButton'
import ResponsiveTable from '../ResponsiveTable'
import NodeForm from './NodeForm'
import NodeHeader from './NodeHeader'
import NodePlaceholder from './NodePlaceholder'
import NodeResults from './NodeResults'
export const nodeQueryInputSchema = createSortingInputSchema(NodeSortingByEnum)
.extend(
{
search: transform(
z.string().optional(),
stringTrimmed,
z.string()
)
}
)
export default function NodeSearch (): ReactElement {
const matomo = useMatomo()
const pathname = usePathname()
const searchParams = useSearchParams()
const router = useRouter()
let routerQuery: NodeQueryInput
try {
routerQuery = nodeQueryInputSchema.parse(Object.fromEntries(searchParams))
} catch (e) {
routerQuery = {
search: '',
sortBy: NodeSortingByEnum.RefreshedAt,
sortWay: SortingWayEnum.Desc
}
}
console.log('Router query', routerQuery)
const [query, setQuery] = useState<NodeQueryInput>(routerQuery)
const [page, setPage] = useState<number>(0)
const [pageLoading, setPageLoading] = useState<boolean>(false)
const { loading, error, data, fetchMore, refetch } = useQuery(ListNodesDocument, {
variables: {
query,
paging: {
page: 0
}
}
})
useEffect(() => {
matomo.trackEvent({
category: 'nodes',
action: 'next-page',
customDimensions: [
{
value: page.toString(),
id: 1
}
]
})
}, [page])
useEffect((): void => {
router.push(`${pathname ?? ''}?${createUrlSearchParams(query).toString()}`)
matomo.trackEvent({
category: 'nodes',
action: 'new-search'
})
}, [query])
const handleQueryChange = (query: FeedQueryInput): void => {
console.info('Query changed', { query })
setQuery(query)
setPage(0)
}
const handleSearchSubmit = async (): Promise<void> => {
setPageLoading(true)
setQuery(query)
setPage(0)
await refetch({ paging: { page: 0 } })
setPageLoading(false)
}
const handleLoadMore = async (): Promise<void> => {
setPage(page + 1)
console.info('Loading next page', { query, page })
setPageLoading(true)
await fetchMore({
variables: {
paging: { page: page + 1 }
},
updateQuery: (previousData, { fetchMoreResult }) => {
console.log('more', {
previousData, fetchMoreResult
})
if (undefined === fetchMoreResult?.listNodes?.items) {
return previousData
}
if (undefined === previousData?.listNodes?.items) {
return fetchMoreResult
}
fetchMoreResult.listNodes.items = [
...previousData.listNodes.items,
...fetchMoreResult.listNodes.items
]
return fetchMoreResult
}
})
setPageLoading(false)
}
const toggleSort = (sortBy: NodeSortingByEnum): void => {
const sortWay = query.sortBy === sortBy && query.sortWay === SortingWayEnum.Asc ? SortingWayEnum.Desc : SortingWayEnum.Asc
matomo.trackEvent({
category: 'nodes',
action: 'sort',
customDimensions: [
{
value: `${sortBy} ${sortWay}`,
id: 2
}
]
})
setQuery({
...query,
sortBy,
sortWay
})
}
return (
<>
<NodeForm query={query} onQueryChange={handleQueryChange} onSubmit={handleSearchSubmit}/>
<ResponsiveTable>
<NodeHeader onSortToggle={toggleSort} query={query}/>
<Loader loading={loading || pageLoading} showBottom={true} placeholder={(<NodePlaceholder/>)}>
<NodeResults nodes={data?.listNodes?.items}/>
</Loader>
</ResponsiveTable>
<LoadMoreButton onClick={handleLoadMore}
show={!loading && !pageLoading && data?.listNodes?.paging?.hasNext === true}/>
<ErrorMessage message={error?.message}/>
</>
)
}