Browse Source

enhancement: skip fetching to improve user experience when switching … (#2580)

Rozstone 1 year ago
parent
commit
f1cbd55007

+ 3 - 1
web/app/components/base/logo/logo-site.tsx

@@ -1,15 +1,17 @@
 import type { FC } from 'react'
+import classNames from 'classnames'
 
 type LogoSiteProps = {
   className?: string
 }
+
 const LogoSite: FC<LogoSiteProps> = ({
   className,
 }) => {
   return (
     <img
       src='/logo/logo-site.png'
-      className={`block w-auto h-10 ${className}`}
+      className={classNames('block w-auto h-10', className)}
       alt='logo'
     />
   )

+ 51 - 31
web/app/components/explore/app-list/index.tsx

@@ -1,13 +1,14 @@
 'use client'
 import type { FC } from 'react'
-import React, { useEffect } from 'react'
+import React from 'react'
 import { useRouter } from 'next/navigation'
 import { useTranslation } from 'react-i18next'
 import { useContext } from 'use-context-selector'
+import useSWR from 'swr'
 import Toast from '../../base/toast'
 import s from './style.module.css'
 import ExploreContext from '@/context/explore-context'
-import type { App, AppCategory } from '@/models/explore'
+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'
@@ -25,34 +26,44 @@ const Apps: FC = () => {
   const { isCurrentWorkspaceManager } = useAppContext()
   const router = useRouter()
   const { hasEditPermission } = useContext(ExploreContext)
+  const allCategoriesEn = t('explore.apps.allCategories', { lng: 'en' })
   const [currCategory, setCurrCategory] = useTabSearchParams({
-    defaultTab: '',
+    defaultTab: allCategoriesEn,
   })
-  const [allList, setAllList] = React.useState<App[]>([])
-  const [isLoaded, setIsLoaded] = React.useState(false)
+  const {
+    data: { categories, allList },
+    isLoading,
+  } = useSWR(
+    ['/explore/apps'],
+    () =>
+      fetchAppList().then(({ categories, recommended_apps }) => ({
+        categories,
+        allList: recommended_apps.sort((a, b) => a.position - b.position),
+      })),
+    {
+      fallbackData: {
+        categories: [],
+        allList: [],
+      },
+    },
+  )
 
   const currList = (() => {
-    if (currCategory === '')
+    if (currCategory === allCategoriesEn)
       return allList
     return allList.filter(item => item.category === currCategory)
   })()
 
-  const [categories, setCategories] = React.useState<AppCategory[]>([])
-  useEffect(() => {
-    (async () => {
-      const { categories, recommended_apps }: any = await fetchAppList()
-      const sortedRecommendedApps = [...recommended_apps]
-      sortedRecommendedApps.sort((a, b) => a.position - b.position) // position from small to big
-      setCategories(categories)
-      setAllList(sortedRecommendedApps)
-      setIsLoaded(true)
-    })()
-  }, [])
-
   const [currApp, setCurrApp] = React.useState<App | null>(null)
   const [isShowCreateModal, setIsShowCreateModal] = React.useState(false)
-  const onCreate: CreateAppModalProps['onConfirm'] = async ({ name, icon, icon_background }) => {
-    const { app_model_config: model_config } = await fetchAppDetail(currApp?.app.id as string)
+  const onCreate: CreateAppModalProps['onConfirm'] = async ({
+    name,
+    icon,
+    icon_background,
+  }) => {
+    const { app_model_config: model_config } = await fetchAppDetail(
+      currApp?.app.id as string,
+    )
 
     try {
       const app = await createApp({
@@ -68,36 +79,45 @@ const Apps: FC = () => {
         message: t('app.newApp.appCreated'),
       })
       localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
-      router.push(`/app/${app.id}/${isCurrentWorkspaceManager ? 'configuration' : 'overview'}`)
+      router.push(
+        `/app/${app.id}/${
+          isCurrentWorkspaceManager ? 'configuration' : 'overview'
+        }`,
+      )
     }
     catch (e) {
       Toast.notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
     }
   }
 
-  if (!isLoaded) {
+  if (!isLoading) {
     return (
-      <div className='flex h-full items-center'>
-        <Loading type='area' />
+      <div className="flex h-full items-center">
+        <Loading type="area" />
       </div>
     )
   }
 
   return (
-    <div className='h-full flex flex-col border-l border-gray-200'>
-      <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 className="h-full flex flex-col border-l border-gray-200">
+      <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>
       <Category
-        className='mt-6 px-12'
+        className="mt-6 px-12"
         list={categories}
         value={currCategory}
         onChange={setCurrCategory}
       />
-      <div className='relative flex flex-1 mt-6 pb-6 flex-col overflow-auto bg-gray-100 shrink-0 grow'>
+      <div className="relative flex flex-1 mt-6 pb-6 flex-col overflow-auto bg-gray-100 shrink-0 grow">
         <nav
-          className={`${s.appList} grid content-start gap-4 px-6 sm:px-12 shrink-0`}>
+          className={`${s.appList} grid content-start gap-4 px-6 sm:px-12 shrink-0`}
+        >
           {currList.map(app => (
             <AppCard
               key={app.app_id}

+ 1 - 1
web/app/components/header/index.tsx

@@ -54,7 +54,7 @@ const Header = () => {
         </div>}
         {!isMobile && <>
           <Link href="/apps" className='flex items-center mr-4'>
-            <LogoSite />
+            <LogoSite className='object-contain' />
           </Link>
           <GithubStar />
         </>}

+ 1 - 1
web/models/explore.ts

@@ -16,7 +16,7 @@ export type App = {
   app_id: string
   description: string
   copyright: string
-  privacy_policy: string
+  privacy_policy: string | null
   category: AppCategory
   position: number
   is_listed: boolean

+ 5 - 1
web/service/explore.ts

@@ -1,7 +1,11 @@
 import { del, get, patch, post } from './base'
+import type { App, AppCategory } from '@/models/explore'
 
 export const fetchAppList = () => {
-  return get('/explore/apps')
+  return get<{
+    categories: AppCategory[]
+    recommended_apps: App[]
+  }>('/explore/apps')
 }
 
 export const fetchAppDetail = (id: string): Promise<any> => {