fix: marketplace list

pull/12372/head
StyleZhang 1 year ago
parent 0e419a7a16
commit 0e70e72594

@ -28,6 +28,7 @@ import type {
import { DEFAULT_SORT } from './constants' import { DEFAULT_SORT } from './constants'
import { import {
useMarketplaceCollectionsAndPlugins, useMarketplaceCollectionsAndPlugins,
useMarketplaceContainerScroll,
useMarketplacePlugins, useMarketplacePlugins,
} from './hooks' } from './hooks'
import { import {
@ -51,7 +52,7 @@ export type MarketplaceContextValue = {
resetPlugins: () => void resetPlugins: () => void
sort: PluginsSort sort: PluginsSort
handleSortChange: (sort: PluginsSort) => void handleSortChange: (sort: PluginsSort) => void
handleQueryPluginsWhenNoCollection: () => void handleQueryPlugins: () => void
marketplaceCollectionsFromClient?: MarketplaceCollection[] marketplaceCollectionsFromClient?: MarketplaceCollection[]
setMarketplaceCollectionsFromClient: (collections: MarketplaceCollection[]) => void setMarketplaceCollectionsFromClient: (collections: MarketplaceCollection[]) => void
marketplaceCollectionPluginsMapFromClient?: Record<string, Plugin[]> marketplaceCollectionPluginsMapFromClient?: Record<string, Plugin[]>
@ -75,7 +76,7 @@ export const MarketplaceContext = createContext<MarketplaceContextValue>({
resetPlugins: () => {}, resetPlugins: () => {},
sort: DEFAULT_SORT, sort: DEFAULT_SORT,
handleSortChange: () => {}, handleSortChange: () => {},
handleQueryPluginsWhenNoCollection: () => {}, handleQueryPlugins: () => {},
marketplaceCollectionsFromClient: [], marketplaceCollectionsFromClient: [],
setMarketplaceCollectionsFromClient: () => {}, setMarketplaceCollectionsFromClient: () => {},
marketplaceCollectionPluginsMapFromClient: {}, marketplaceCollectionPluginsMapFromClient: {},
@ -88,6 +89,7 @@ type MarketplaceContextProviderProps = {
children: ReactNode children: ReactNode
searchParams?: SearchParams searchParams?: SearchParams
shouldExclude?: boolean shouldExclude?: boolean
scrollContainerId?: string
} }
export function useMarketplaceContext(selector: (value: MarketplaceContextValue) => any) { export function useMarketplaceContext(selector: (value: MarketplaceContextValue) => any) {
@ -98,6 +100,7 @@ export const MarketplaceContextProvider = ({
children, children,
searchParams, searchParams,
shouldExclude, shouldExclude,
scrollContainerId,
}: MarketplaceContextProviderProps) => { }: MarketplaceContextProviderProps) => {
const { data, isSuccess } = useInstalledPluginList(!shouldExclude) const { data, isSuccess } = useInstalledPluginList(!shouldExclude)
const exclude = useMemo(() => { const exclude = useMemo(() => {
@ -131,6 +134,7 @@ export const MarketplaceContextProvider = ({
} = useMarketplaceCollectionsAndPlugins() } = useMarketplaceCollectionsAndPlugins()
const { const {
plugins, plugins,
total: pluginsTotal,
resetPlugins, resetPlugins,
queryPlugins, queryPlugins,
queryPluginsWithDebounced, queryPluginsWithDebounced,
@ -161,34 +165,60 @@ export const MarketplaceContextProvider = ({
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [queryPlugins, queryMarketplaceCollectionsAndPlugins, isSuccess, exclude]) }, [queryPlugins, queryMarketplaceCollectionsAndPlugins, isSuccess, exclude])
const handleSearchPluginTextChange = useCallback((text: string) => { const handleQueryMarketplaceCollectionsAndPlugins = useCallback(() => {
setSearchPluginText(text) queryMarketplaceCollectionsAndPlugins({
searchPluginTextRef.current = text category: activePluginTypeRef.current === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : activePluginTypeRef.current,
setPage(1) condition: getMarketplaceListCondition(activePluginTypeRef.current),
pageRef.current = 1 exclude,
type: getMarketplaceListFilterType(activePluginTypeRef.current),
})
resetPlugins()
}, [exclude, queryMarketplaceCollectionsAndPlugins, resetPlugins])
if (!searchPluginTextRef.current && !filterPluginTagsRef.current.length) { const handleQueryPlugins = useCallback((debounced?: boolean) => {
queryMarketplaceCollectionsAndPlugins({ if (debounced) {
queryPluginsWithDebounced({
query: searchPluginTextRef.current,
category: activePluginTypeRef.current === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : activePluginTypeRef.current, category: activePluginTypeRef.current === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : activePluginTypeRef.current,
condition: getMarketplaceListCondition(activePluginTypeRef.current), tags: filterPluginTagsRef.current,
sortBy: sortRef.current.sortBy,
sortOrder: sortRef.current.sortOrder,
exclude, exclude,
type: getMarketplaceListFilterType(activePluginTypeRef.current), type: getMarketplaceListFilterType(activePluginTypeRef.current),
page: pageRef.current,
}) })
resetPlugins() }
else {
queryPlugins({
query: searchPluginTextRef.current,
category: activePluginTypeRef.current === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : activePluginTypeRef.current,
tags: filterPluginTagsRef.current,
sortBy: sortRef.current.sortBy,
sortOrder: sortRef.current.sortOrder,
exclude,
type: getMarketplaceListFilterType(activePluginTypeRef.current),
page: pageRef.current,
})
}
}, [exclude, queryPluginsWithDebounced, queryPlugins])
const handleQuery = useCallback((debounced?: boolean) => {
if (!searchPluginTextRef.current && !filterPluginTagsRef.current.length) {
handleQueryMarketplaceCollectionsAndPlugins()
return return
} }
queryPluginsWithDebounced({ handleQueryPlugins(debounced)
query: text, }, [handleQueryMarketplaceCollectionsAndPlugins, handleQueryPlugins])
category: activePluginTypeRef.current === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : activePluginTypeRef.current,
tags: filterPluginTagsRef.current, const handleSearchPluginTextChange = useCallback((text: string) => {
sortBy: sortRef.current.sortBy, setSearchPluginText(text)
sortOrder: sortRef.current.sortOrder, searchPluginTextRef.current = text
exclude, setPage(1)
page: pageRef.current, pageRef.current = 1
})
}, [queryPluginsWithDebounced, queryMarketplaceCollectionsAndPlugins, resetPlugins, exclude]) handleQuery(true)
}, [handleQuery])
const handleFilterPluginTagsChange = useCallback((tags: string[]) => { const handleFilterPluginTagsChange = useCallback((tags: string[]) => {
setFilterPluginTags(tags) setFilterPluginTags(tags)
@ -196,29 +226,8 @@ export const MarketplaceContextProvider = ({
setPage(1) setPage(1)
pageRef.current = 1 pageRef.current = 1
if (!searchPluginTextRef.current && !filterPluginTagsRef.current.length) { handleQuery()
queryMarketplaceCollectionsAndPlugins({ }, [handleQuery])
category: activePluginTypeRef.current === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : activePluginTypeRef.current,
condition: getMarketplaceListCondition(activePluginTypeRef.current),
exclude,
type: getMarketplaceListFilterType(activePluginTypeRef.current),
})
resetPlugins()
return
}
queryPlugins({
query: searchPluginTextRef.current,
category: activePluginTypeRef.current === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : activePluginTypeRef.current,
tags,
sortBy: sortRef.current.sortBy,
sortOrder: sortRef.current.sortOrder,
exclude,
type: getMarketplaceListFilterType(activePluginTypeRef.current),
page: pageRef.current,
})
}, [queryPlugins, resetPlugins, queryMarketplaceCollectionsAndPlugins, exclude])
const handleActivePluginTypeChange = useCallback((type: string) => { const handleActivePluginTypeChange = useCallback((type: string) => {
setActivePluginType(type) setActivePluginType(type)
@ -226,57 +235,8 @@ export const MarketplaceContextProvider = ({
setPage(1) setPage(1)
pageRef.current = 1 pageRef.current = 1
if (!searchPluginTextRef.current && !filterPluginTagsRef.current.length) { handleQuery()
queryMarketplaceCollectionsAndPlugins({ }, [handleQuery])
category: type === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : type,
condition: getMarketplaceListCondition(type),
exclude,
type: getMarketplaceListFilterType(activePluginTypeRef.current),
})
resetPlugins()
return
}
queryPlugins({
query: searchPluginTextRef.current,
category: type === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : type,
tags: filterPluginTagsRef.current,
sortBy: sortRef.current.sortBy,
sortOrder: sortRef.current.sortOrder,
exclude,
type: getMarketplaceListFilterType(activePluginTypeRef.current),
page: pageRef.current,
})
}, [queryPlugins, resetPlugins, queryMarketplaceCollectionsAndPlugins, exclude])
const handlePageChange = useCallback(() => {
setPage(pageRef.current + 1)
pageRef.current++
if (!searchPluginTextRef.current && !filterPluginTagsRef.current.length) {
queryMarketplaceCollectionsAndPlugins({
category: activePluginTypeRef.current === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : activePluginTypeRef.current,
condition: getMarketplaceListCondition(activePluginTypeRef.current),
exclude,
type: getMarketplaceListFilterType(activePluginTypeRef.current),
})
resetPlugins()
return
}
queryPlugins({
query: searchPluginTextRef.current,
category: activePluginTypeRef.current === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : activePluginTypeRef.current,
tags: filterPluginTagsRef.current,
sortBy: sortRef.current.sortBy,
sortOrder: sortRef.current.sortOrder,
exclude,
type: getMarketplaceListFilterType(activePluginTypeRef.current),
page: pageRef.current,
})
}, [exclude, queryPlugins, queryMarketplaceCollectionsAndPlugins, resetPlugins])
const handleSortChange = useCallback((sort: PluginsSort) => { const handleSortChange = useCallback((sort: PluginsSort) => {
setSort(sort) setSort(sort)
@ -284,32 +244,19 @@ export const MarketplaceContextProvider = ({
setPage(1) setPage(1)
pageRef.current = 1 pageRef.current = 1
queryPlugins({ handleQueryPlugins()
query: searchPluginTextRef.current, }, [handleQueryPlugins])
category: activePluginTypeRef.current === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : activePluginTypeRef.current,
tags: filterPluginTagsRef.current,
sortBy: sortRef.current.sortBy,
sortOrder: sortRef.current.sortOrder,
exclude,
type: getMarketplaceListFilterType(activePluginTypeRef.current),
page: pageRef.current,
})
}, [queryPlugins, exclude])
const handleQueryPluginsWhenNoCollection = useCallback(() => { const handlePageChange = useCallback(() => {
queryPlugins({ if (pluginsTotal && plugins && pluginsTotal > plugins.length && (!!searchPluginTextRef.current || !!filterPluginTagsRef.current.length)) {
query: searchPluginTextRef.current, setPage(pageRef.current + 1)
category: activePluginTypeRef.current === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : activePluginTypeRef.current, pageRef.current++
tags: filterPluginTagsRef.current,
sortBy: sortRef.current.sortBy, handleQueryPlugins()
sortOrder: sortRef.current.sortOrder, }
exclude, }, [handleQueryPlugins, plugins, pluginsTotal])
type: getMarketplaceListFilterType(activePluginTypeRef.current),
page: pageRef.current,
})
}, [exclude, queryPlugins])
// useMarketplaceContainerScroll(handlePageChange) useMarketplaceContainerScroll(handlePageChange, scrollContainerId)
return ( return (
<MarketplaceContext.Provider <MarketplaceContext.Provider
@ -328,7 +275,7 @@ export const MarketplaceContextProvider = ({
resetPlugins, resetPlugins,
sort, sort,
handleSortChange, handleSortChange,
handleQueryPluginsWhenNoCollection, handleQueryPlugins,
marketplaceCollectionsFromClient, marketplaceCollectionsFromClient,
setMarketplaceCollectionsFromClient, setMarketplaceCollectionsFromClient,
marketplaceCollectionPluginsMapFromClient, marketplaceCollectionPluginsMapFromClient,

@ -59,27 +59,46 @@ export const useMarketplaceCollectionsAndPlugins = () => {
export const useMarketplacePlugins = () => { export const useMarketplacePlugins = () => {
const { const {
data, data,
mutate, mutateAsync,
reset, reset,
isPending, isPending,
} = useMutationPluginsFromMarketplace() } = useMutationPluginsFromMarketplace()
const [prevPlugins, setPrevPlugins] = useState<Plugin[] | undefined>()
const resetPlugins = useCallback(() => {
reset()
setPrevPlugins(undefined)
}, [reset])
const handleUpdatePlugins = useCallback((pluginsSearchParams: PluginsSearchParams) => {
mutateAsync(pluginsSearchParams).then((res) => {
const currentPage = pluginsSearchParams.page || 1
const resPlugins = res.data.plugins
if (currentPage > 1) {
setPrevPlugins(prevPlugins => [...(prevPlugins || []), ...resPlugins.map((plugin) => {
return getFormattedPlugin(plugin)
})])
}
else {
setPrevPlugins(resPlugins.map((plugin) => {
return getFormattedPlugin(plugin)
}))
}
})
}, [mutateAsync])
const queryPlugins = useCallback((pluginsSearchParams: PluginsSearchParams) => { const queryPlugins = useCallback((pluginsSearchParams: PluginsSearchParams) => {
mutate(pluginsSearchParams) handleUpdatePlugins(pluginsSearchParams)
}, [mutate]) }, [handleUpdatePlugins])
const { run: queryPluginsWithDebounced } = useDebounceFn((pluginsSearchParams: PluginsSearchParams) => { const { run: queryPluginsWithDebounced } = useDebounceFn((pluginsSearchParams: PluginsSearchParams) => {
mutate(pluginsSearchParams) handleUpdatePlugins(pluginsSearchParams)
}, { }, {
wait: 500, wait: 500,
}) })
return { return {
plugins: data?.data?.plugins.map((plugin) => { plugins: prevPlugins,
return getFormattedPlugin(plugin)
}),
total: data?.data?.total, total: data?.data?.total,
resetPlugins: reset, resetPlugins,
queryPlugins, queryPlugins,
queryPluginsWithDebounced, queryPluginsWithDebounced,
isLoading: isPending, isLoading: isPending,
@ -97,8 +116,11 @@ export const useMixedTranslation = (localeFromOuter?: string) => {
} }
} }
export const useMarketplaceContainerScroll = (callback: () => void) => { export const useMarketplaceContainerScroll = (
const container = document.getElementById('marketplace-container') callback: () => void,
scrollContainerId = 'marketplace-container',
) => {
const container = document.getElementById(scrollContainerId)
const handleScroll = useCallback((e: Event) => { const handleScroll = useCallback((e: Event) => {
const target = e.target as HTMLDivElement const target = e.target as HTMLDivElement

@ -14,6 +14,8 @@ type MarketplaceProps = {
shouldExclude?: boolean shouldExclude?: boolean
searchParams?: SearchParams searchParams?: SearchParams
pluginTypeSwitchClassName?: string pluginTypeSwitchClassName?: string
intersectionContainerId?: string
scrollContainerId?: string
} }
const Marketplace = async ({ const Marketplace = async ({
locale, locale,
@ -21,6 +23,8 @@ const Marketplace = async ({
shouldExclude, shouldExclude,
searchParams, searchParams,
pluginTypeSwitchClassName, pluginTypeSwitchClassName,
intersectionContainerId,
scrollContainerId,
}: MarketplaceProps) => { }: MarketplaceProps) => {
let marketplaceCollections: any = [] let marketplaceCollections: any = []
let marketplaceCollectionPluginsMap = {} let marketplaceCollectionPluginsMap = {}
@ -32,9 +36,13 @@ const Marketplace = async ({
return ( return (
<TanstackQueryIniter> <TanstackQueryIniter>
<MarketplaceContextProvider searchParams={searchParams} shouldExclude={shouldExclude}> <MarketplaceContextProvider
searchParams={searchParams}
shouldExclude={shouldExclude}
scrollContainerId={scrollContainerId}
>
<Description locale={locale} /> <Description locale={locale} />
<IntersectionLine /> <IntersectionLine intersectionContainerId={intersectionContainerId} />
<SearchBoxWrapper locale={locale} /> <SearchBoxWrapper locale={locale} />
<PluginTypeSwitch <PluginTypeSwitch
locale={locale} locale={locale}

@ -3,12 +3,13 @@ import { useMarketplaceContext } from '@/app/components/plugins/marketplace/cont
export const useScrollIntersection = ( export const useScrollIntersection = (
anchorRef: React.RefObject<HTMLDivElement>, anchorRef: React.RefObject<HTMLDivElement>,
intersectionContainerId = 'marketplace-container',
) => { ) => {
const intersected = useMarketplaceContext(v => v.intersected) const intersected = useMarketplaceContext(v => v.intersected)
const setIntersected = useMarketplaceContext(v => v.setIntersected) const setIntersected = useMarketplaceContext(v => v.setIntersected)
useEffect(() => { useEffect(() => {
const container = document.getElementById('marketplace-container') const container = document.getElementById(intersectionContainerId)
let observer: IntersectionObserver | undefined let observer: IntersectionObserver | undefined
if (container && anchorRef.current) { if (container && anchorRef.current) {
observer = new IntersectionObserver((entries) => { observer = new IntersectionObserver((entries) => {
@ -25,5 +26,5 @@ export const useScrollIntersection = (
observer.observe(anchorRef.current) observer.observe(anchorRef.current)
} }
return () => observer?.disconnect() return () => observer?.disconnect()
}, [anchorRef, intersected, setIntersected]) }, [anchorRef, intersected, setIntersected, intersectionContainerId])
} }

@ -3,10 +3,15 @@
import { useRef } from 'react' import { useRef } from 'react'
import { useScrollIntersection } from './hooks' import { useScrollIntersection } from './hooks'
const IntersectionLine = () => { type IntersectionLineProps = {
intersectionContainerId?: string
}
const IntersectionLine = ({
intersectionContainerId,
}: IntersectionLineProps) => {
const ref = useRef<HTMLDivElement>(null) const ref = useRef<HTMLDivElement>(null)
useScrollIntersection(ref) useScrollIntersection(ref, intersectionContainerId)
return ( return (
<div ref={ref} className='mb-4 h-[1px] bg-transparent'></div> <div ref={ref} className='mb-4 h-[1px] bg-transparent'></div>

@ -26,18 +26,19 @@ const ListWrapper = ({
const marketplaceCollectionPluginsMapFromClient = useMarketplaceContext(v => v.marketplaceCollectionPluginsMapFromClient) const marketplaceCollectionPluginsMapFromClient = useMarketplaceContext(v => v.marketplaceCollectionPluginsMapFromClient)
const isLoading = useMarketplaceContext(v => v.isLoading) const isLoading = useMarketplaceContext(v => v.isLoading)
const isSuccessCollections = useMarketplaceContext(v => v.isSuccessCollections) const isSuccessCollections = useMarketplaceContext(v => v.isSuccessCollections)
const handleQueryPluginsWhenNoCollection = useMarketplaceContext(v => v.handleQueryPluginsWhenNoCollection) const handleQueryPlugins = useMarketplaceContext(v => v.handleQueryPlugins)
const page = useMarketplaceContext(v => v.page)
useEffect(() => { useEffect(() => {
if (!marketplaceCollectionsFromClient?.length && isSuccessCollections) if (!marketplaceCollectionsFromClient?.length && isSuccessCollections)
handleQueryPluginsWhenNoCollection() handleQueryPlugins()
}, [handleQueryPluginsWhenNoCollection, marketplaceCollections, marketplaceCollectionsFromClient, isSuccessCollections]) }, [handleQueryPlugins, marketplaceCollections, marketplaceCollectionsFromClient, isSuccessCollections])
return ( return (
<div className='relative flex flex-col grow px-12 py-2 bg-background-default-subtle'> <div className='relative flex flex-col grow px-12 py-2 bg-background-default-subtle'>
{ {
plugins && ( plugins && (
<div className='flex items-center mb-4 pt-3'> <div className='top-5 flex items-center mb-4 pt-3'>
<div className='title-xl-semi-bold text-text-primary'>{t('plugin.marketplace.pluginsResult', { num: plugins.length })}</div> <div className='title-xl-semi-bold text-text-primary'>{t('plugin.marketplace.pluginsResult', { num: plugins.length })}</div>
<div className='mx-3 w-[1px] h-3.5 bg-divider-regular'></div> <div className='mx-3 w-[1px] h-3.5 bg-divider-regular'></div>
<SortDropdown /> <SortDropdown />
@ -45,14 +46,14 @@ const ListWrapper = ({
) )
} }
{ {
isLoading && ( isLoading && page === 1 && (
<div className='absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2'> <div className='absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2'>
<Loading /> <Loading />
</div> </div>
) )
} }
{ {
!isLoading && ( (!isLoading || page > 1) && (
<List <List
marketplaceCollections={marketplaceCollectionsFromClient || marketplaceCollections} marketplaceCollections={marketplaceCollectionsFromClient || marketplaceCollections}
marketplaceCollectionPluginsMap={marketplaceCollectionPluginsMapFromClient || marketplaceCollectionPluginsMap} marketplaceCollectionPluginsMap={marketplaceCollectionPluginsMapFromClient || marketplaceCollectionPluginsMap}

@ -298,11 +298,12 @@ export const useMutationPluginsFromMarketplace = () => {
exclude, exclude,
type, type,
page = 1, page = 1,
pageSize = 20,
} = pluginsSearchParams } = pluginsSearchParams
return postMarketplace<{ data: PluginsFromMarketplaceResponse }>('/plugins/search/basic', { return postMarketplace<{ data: PluginsFromMarketplaceResponse }>('/plugins/search/basic', {
body: { body: {
page, page,
page_size: 100, page_size: pageSize,
query, query,
sort_by: sortBy, sort_by: sortBy,
sort_order: sortOrder, sort_order: sortOrder,

Loading…
Cancel
Save