| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 | 
							- 'use client'
 
- import React, { useMemo, useState } from 'react'
 
- import { useRouter } from 'next/navigation'
 
- import { useTranslation } from 'react-i18next'
 
- import { useContext } from 'use-context-selector'
 
- import useSWR from 'swr'
 
- import { useDebounceFn } from 'ahooks'
 
- import Toast from '../../base/toast'
 
- import s from './style.module.css'
 
- import cn from '@/utils/classnames'
 
- import ExploreContext from '@/context/explore-context'
 
- import type { App } from '@/models/explore'
 
- import Category from '@/app/components/explore/category'
 
- import AppCard from '@/app/components/explore/app-card'
 
- import { fetchAppDetail, fetchAppList } from '@/service/explore'
 
- import { importApp } from '@/service/apps'
 
- import { useTabSearchParams } from '@/hooks/use-tab-searchparams'
 
- import CreateAppModal from '@/app/components/explore/create-app-modal'
 
- import AppTypeSelector from '@/app/components/app/type-selector'
 
- import type { CreateAppModalProps } from '@/app/components/explore/create-app-modal'
 
- import Loading from '@/app/components/base/loading'
 
- import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
 
- import { useAppContext } from '@/context/app-context'
 
- import { getRedirection } from '@/utils/app-redirection'
 
- import SearchInput from '@/app/components/base/search-input'
 
- type AppsProps = {
 
-   pageType?: PageType
 
-   onSuccess?: () => void
 
- }
 
- export enum PageType {
 
-   EXPLORE = 'explore',
 
-   CREATE = 'create',
 
- }
 
- const Apps = ({
 
-   pageType = PageType.EXPLORE,
 
-   onSuccess,
 
- }: AppsProps) => {
 
-   const { t } = useTranslation()
 
-   const { isCurrentWorkspaceEditor } = useAppContext()
 
-   const { push } = useRouter()
 
-   const { hasEditPermission } = useContext(ExploreContext)
 
-   const allCategoriesEn = t('explore.apps.allCategories', { lng: 'en' })
 
-   const [keywords, setKeywords] = useState('')
 
-   const [searchKeywords, setSearchKeywords] = useState('')
 
-   const { run: handleSearch } = useDebounceFn(() => {
 
-     setSearchKeywords(keywords)
 
-   }, { wait: 500 })
 
-   const handleKeywordsChange = (value: string) => {
 
-     setKeywords(value)
 
-     handleSearch()
 
-   }
 
-   const [currentType, setCurrentType] = useState<string>('')
 
-   const [currCategory, setCurrCategory] = useTabSearchParams({
 
-     defaultTab: allCategoriesEn,
 
-     disableSearchParams: pageType !== PageType.EXPLORE,
 
-   })
 
-   const {
 
-     data: { categories, allList },
 
-   } = useSWR(
 
-     ['/explore/apps'],
 
-     () =>
 
-       fetchAppList().then(({ categories, recommended_apps }) => ({
 
-         categories,
 
-         allList: recommended_apps.sort((a, b) => a.position - b.position),
 
-       })),
 
-     {
 
-       fallbackData: {
 
-         categories: [],
 
-         allList: [],
 
-       },
 
-     },
 
-   )
 
-   const filteredList = useMemo(() => {
 
-     if (currCategory === allCategoriesEn) {
 
-       if (!currentType)
 
-         return allList
 
-       else if (currentType === 'chatbot')
 
-         return allList.filter(item => (item.app.mode === 'chat' || item.app.mode === 'advanced-chat'))
 
-       else if (currentType === 'agent')
 
-         return allList.filter(item => (item.app.mode === 'agent-chat'))
 
-       else
 
-         return allList.filter(item => (item.app.mode === 'workflow'))
 
-     }
 
-     else {
 
-       if (!currentType)
 
-         return allList.filter(item => item.category === currCategory)
 
-       else if (currentType === 'chatbot')
 
-         return allList.filter(item => (item.app.mode === 'chat' || item.app.mode === 'advanced-chat') && item.category === currCategory)
 
-       else if (currentType === 'agent')
 
-         return allList.filter(item => (item.app.mode === 'agent-chat') && item.category === currCategory)
 
-       else
 
-         return allList.filter(item => (item.app.mode === 'workflow') && item.category === currCategory)
 
-     }
 
-   }, [currentType, currCategory, allCategoriesEn, allList])
 
-   const searchFilteredList = useMemo(() => {
 
-     if (!searchKeywords || !filteredList || filteredList.length === 0)
 
-       return filteredList
 
-     const lowerCaseSearchKeywords = searchKeywords.toLowerCase()
 
-     return filteredList.filter(item =>
 
-       item.app && item.app.name && item.app.name.toLowerCase().includes(lowerCaseSearchKeywords),
 
-     )
 
-   }, [searchKeywords, filteredList])
 
-   const [currApp, setCurrApp] = React.useState<App | null>(null)
 
-   const [isShowCreateModal, setIsShowCreateModal] = React.useState(false)
 
-   const onCreate: CreateAppModalProps['onConfirm'] = async ({
 
-     name,
 
-     icon_type,
 
-     icon,
 
-     icon_background,
 
-     description,
 
-   }) => {
 
-     const { export_data } = await fetchAppDetail(
 
-       currApp?.app.id as string,
 
-     )
 
-     try {
 
-       const app = await importApp({
 
-         data: export_data,
 
-         name,
 
-         icon_type,
 
-         icon,
 
-         icon_background,
 
-         description,
 
-       })
 
-       setIsShowCreateModal(false)
 
-       Toast.notify({
 
-         type: 'success',
 
-         message: t('app.newApp.appCreated'),
 
-       })
 
-       if (onSuccess)
 
-         onSuccess()
 
-       localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
 
-       getRedirection(isCurrentWorkspaceEditor, app, push)
 
-     }
 
-     catch (e) {
 
-       Toast.notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
 
-     }
 
-   }
 
-   if (!categories || categories.length === 0) {
 
-     return (
 
-       <div className="flex h-full items-center">
 
-         <Loading type="area" />
 
-       </div>
 
-     )
 
-   }
 
-   return (
 
-     <div className={cn(
 
-       'flex flex-col',
 
-       pageType === PageType.EXPLORE ? 'h-full border-l border-gray-200' : 'h-[calc(100%-56px)]',
 
-     )}>
 
-       {pageType === PageType.EXPLORE && (
 
-         <div className='shrink-0 pt-6 px-12'>
 
-           <div className={`mb-1 ${s.textGradient} text-xl font-semibold`}>{t('explore.apps.title')}</div>
 
-           <div className='text-gray-500 text-sm'>{t('explore.apps.description')}</div>
 
-         </div>
 
-       )}
 
-       <div className={cn(
 
-         'flex items-center justify-between mt-6',
 
-         pageType === PageType.EXPLORE ? 'px-12' : 'px-8',
 
-       )}>
 
-         <>
 
-           {pageType !== PageType.EXPLORE && (
 
-             <>
 
-               <AppTypeSelector value={currentType} onChange={setCurrentType}/>
 
-               <div className='mx-2 w-[1px] h-3.5 bg-gray-200'/>
 
-             </>
 
-           )}
 
-           <Category
 
-             list={categories}
 
-             value={currCategory}
 
-             onChange={setCurrCategory}
 
-             allCategoriesEn={allCategoriesEn}
 
-           />
 
-         </>
 
-         <SearchInput value={keywords} onChange={handleKeywordsChange}/>
 
-       </div>
 
-       <div className={cn(
 
-         'relative flex flex-1 pb-6 flex-col overflow-auto bg-gray-100 shrink-0 grow',
 
-         pageType === PageType.EXPLORE ? 'mt-4' : 'mt-0 pt-2',
 
-       )}>
 
-         <nav
 
-           className={cn(
 
-             s.appList,
 
-             'grid content-start shrink-0',
 
-             pageType === PageType.EXPLORE ? 'gap-4 px-6 sm:px-12' : 'gap-3 px-8  sm:!grid-cols-2 md:!grid-cols-3 lg:!grid-cols-4',
 
-           )}>
 
-           {searchFilteredList.map(app => (
 
-             <AppCard
 
-               key={app.app_id}
 
-               isExplore={pageType === PageType.EXPLORE}
 
-               app={app}
 
-               canCreate={hasEditPermission}
 
-               onCreate={() => {
 
-                 setCurrApp(app)
 
-                 setIsShowCreateModal(true)
 
-               }}
 
-             />
 
-           ))}
 
-         </nav>
 
-       </div>
 
-       {isShowCreateModal && (
 
-         <CreateAppModal
 
-           appIconType={currApp?.app.icon_type || 'emoji'}
 
-           appIcon={currApp?.app.icon || ''}
 
-           appIconBackground={currApp?.app.icon_background || ''}
 
-           appIconUrl={currApp?.app.icon_url}
 
-           appName={currApp?.app.name || ''}
 
-           appDescription={currApp?.app.description || ''}
 
-           show={isShowCreateModal}
 
-           onConfirm={onCreate}
 
-           onHide={() => setIsShowCreateModal(false)}
 
-         />
 
-       )}
 
-     </div>
 
-   )
 
- }
 
- export default React.memo(Apps)
 
 
  |