|
@@ -1,11 +1,12 @@
|
|
|
'use client'
|
|
|
|
|
|
-import { useEffect, useRef, useState } from 'react'
|
|
|
+import { useCallback, useEffect, useRef, useState } from 'react'
|
|
|
import useSWRInfinite from 'swr/infinite'
|
|
|
import { useTranslation } from 'react-i18next'
|
|
|
import { useDebounceFn } from 'ahooks'
|
|
|
import AppCard from './AppCard'
|
|
|
import NewAppCard from './NewAppCard'
|
|
|
+import useAppsQueryState from './hooks/useAppsQueryState'
|
|
|
import type { AppListResponse } from '@/models/app'
|
|
|
import { fetchAppList } from '@/service/apps'
|
|
|
import { useAppContext } from '@/context/app-context'
|
|
@@ -54,10 +55,15 @@ const Apps = () => {
|
|
|
const [activeTab, setActiveTab] = useTabSearchParams({
|
|
|
defaultTab: 'all',
|
|
|
})
|
|
|
- const [tagFilterValue, setTagFilterValue] = useState<string[]>([])
|
|
|
- const [tagIDs, setTagIDs] = useState<string[]>([])
|
|
|
- const [keywords, setKeywords] = useState('')
|
|
|
- const [searchKeywords, setSearchKeywords] = useState('')
|
|
|
+ const { query: { tagIDs = [], keywords = '' }, setQuery } = useAppsQueryState()
|
|
|
+ const [tagFilterValue, setTagFilterValue] = useState<string[]>(tagIDs)
|
|
|
+ const [searchKeywords, setSearchKeywords] = useState(keywords)
|
|
|
+ const setKeywords = useCallback((keywords: string) => {
|
|
|
+ setQuery(prev => ({ ...prev, keywords }))
|
|
|
+ }, [setQuery])
|
|
|
+ const setTagIDs = useCallback((tagIDs: string[]) => {
|
|
|
+ setQuery(prev => ({ ...prev, tagIDs }))
|
|
|
+ }, [setQuery])
|
|
|
|
|
|
const { data, isLoading, setSize, mutate } = useSWRInfinite(
|
|
|
(pageIndex: number, previousPageData: AppListResponse) => getKey(pageIndex, previousPageData, activeTab, tagIDs, searchKeywords),
|
|
@@ -81,17 +87,18 @@ const Apps = () => {
|
|
|
}
|
|
|
}, [])
|
|
|
|
|
|
+ const hasMore = data?.at(-1)?.has_more ?? true
|
|
|
useEffect(() => {
|
|
|
let observer: IntersectionObserver | undefined
|
|
|
if (anchorRef.current) {
|
|
|
observer = new IntersectionObserver((entries) => {
|
|
|
- if (entries[0].isIntersecting && !isLoading)
|
|
|
+ if (entries[0].isIntersecting && !isLoading && hasMore)
|
|
|
setSize((size: number) => size + 1)
|
|
|
}, { rootMargin: '100px' })
|
|
|
observer.observe(anchorRef.current)
|
|
|
}
|
|
|
return () => observer?.disconnect()
|
|
|
- }, [isLoading, setSize, anchorRef, mutate])
|
|
|
+ }, [isLoading, setSize, anchorRef, mutate, hasMore])
|
|
|
|
|
|
const { run: handleSearch } = useDebounceFn(() => {
|
|
|
setSearchKeywords(keywords)
|