'use client' import { 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 type { AppListResponse } from '@/models/app' import { fetchAppList } from '@/service/apps' import { useAppContext } from '@/context/app-context' import { NEED_REFRESH_APP_LIST_KEY } from '@/config' import { CheckModal } from '@/hooks/use-pay' import TabSlider from '@/app/components/base/tab-slider' import { SearchLg } from '@/app/components/base/icons/src/vender/line/general' import { XCircle } from '@/app/components/base/icons/src/vender/solid/general' const getKey = ( pageIndex: number, previousPageData: AppListResponse, activeTab: string, keywords: string, ) => { if (!pageIndex || previousPageData.has_more) { const params: any = { url: 'apps', params: { page: pageIndex + 1, limit: 30, name: keywords } } if (activeTab !== 'all') params.params.mode = activeTab return params } return null } const Apps = () => { const { t } = useTranslation() const { isCurrentWorkspaceManager } = useAppContext() const [activeTab, setActiveTab] = useState('all') const [keywords, setKeywords] = useState('') const [searchKeywords, setSearchKeywords] = useState('') const { data, isLoading, setSize, mutate } = useSWRInfinite( (pageIndex: number, previousPageData: AppListResponse) => getKey(pageIndex, previousPageData, activeTab, searchKeywords), fetchAppList, { revalidateFirstPage: false }, ) const anchorRef = useRef(null) const options = [ { value: 'all', text: t('app.types.all') }, { value: 'chat', text: t('app.types.assistant') }, { value: 'completion', text: t('app.types.completion') }, ] useEffect(() => { document.title = `${t('common.menus.apps')} - Dify` if (localStorage.getItem(NEED_REFRESH_APP_LIST_KEY) === '1') { localStorage.removeItem(NEED_REFRESH_APP_LIST_KEY) mutate() } }, [mutate, t]) useEffect(() => { let observer: IntersectionObserver | undefined if (anchorRef.current) { observer = new IntersectionObserver((entries) => { if (entries[0].isIntersecting && !isLoading) setSize((size: number) => size + 1) }, { rootMargin: '100px' }) observer.observe(anchorRef.current) } return () => observer?.disconnect() }, [isLoading, setSize, anchorRef, mutate]) const { run: handleSearch } = useDebounceFn(() => { setSearchKeywords(keywords) }, { wait: 500 }) const handleKeywordsChange = (value: string) => { setKeywords(value) handleSearch() } const handleClear = () => { handleKeywordsChange('') } return ( <>
{ handleKeywordsChange(e.target.value) }} autoComplete="off" /> { keywords && (
) }
) } export default Apps