'use client'
import {
useCallback,
useEffect,
useState,
} from 'react'
import { useAsyncEffect } from 'ahooks'
import { useTranslation } from 'react-i18next'
import { RiLoopLeftLine } from '@remixicon/react'
import { usePathname, useRouter, useSearchParams } from 'next/navigation'
import Tooltip from '../../tooltip'
import {
EmbeddedChatbotContext,
useEmbeddedChatbotContext,
} from './context'
import { useEmbeddedChatbot } from './hooks'
import { isDify } from './utils'
import { useThemeContext } from './theme/theme-context'
import { checkOrSetAccessToken, removeAccessToken } from '@/app/components/share/utils'
import AppUnavailable from '@/app/components/base/app-unavailable'
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
import Loading from '@/app/components/base/loading'
import LogoHeader from '@/app/components/base/logo/logo-embedded-chat-header'
import Header from '@/app/components/base/chat/embedded-chatbot/header'
import ConfigPanel from '@/app/components/base/chat/embedded-chatbot/config-panel'
import ChatWrapper from '@/app/components/base/chat/embedded-chatbot/chat-wrapper'
import cn from '@/utils/classnames'
import useDocumentTitle from '@/hooks/use-document-title'
const Chatbot = () => {
const { t } = useTranslation()
const {
userCanAccess,
isMobile,
appInfoError,
appInfoLoading,
appData,
appPrevChatList,
showConfigPanelBeforeChat,
appChatListDataLoading,
handleNewConversation,
themeBuilder,
isInstalledApp,
} = useEmbeddedChatbotContext()
const chatReady = (!showConfigPanelBeforeChat || !!appPrevChatList.length)
const customConfig = appData?.custom_config
const site = appData?.site
const difyIcon =
useEffect(() => {
themeBuilder?.buildTheme(site?.chat_color_theme, site?.chat_color_theme_inverted)
if (site) {
if (customConfig)
document.title = `${site.title}`
else
document.title = `${site.title} - Powered by Dify`
}
}, [site, customConfig, themeBuilder])
useDocumentTitle(site?.title || 'Chat')
const searchParams = useSearchParams()
const router = useRouter()
const pathname = usePathname()
const getSigninUrl = useCallback(() => {
const params = new URLSearchParams(searchParams)
params.delete('message')
params.set('redirect_url', pathname)
return `/webapp-signin?${params.toString()}`
}, [searchParams, pathname])
const backToHome = useCallback(() => {
removeAccessToken()
const url = getSigninUrl()
router.replace(url)
}, [getSigninUrl, router])
if (appInfoLoading) {
return (
)
}
if (!userCanAccess) {
return
{!isInstalledApp &&
{t('common.userProfile.logout')}}
}
if (appInfoError) {
return (
)
}
return (
{showConfigPanelBeforeChat && !appChatListDataLoading && !appPrevChatList.length && (
)}
{appChatListDataLoading && chatReady && (
)}
{chatReady && !appChatListDataLoading && (
)}
)
}
const EmbeddedChatbotWrapper = () => {
const media = useBreakpoints()
const isMobile = media === MediaType.mobile
const themeBuilder = useThemeContext()
const {
appInfoError,
appInfoLoading,
appData,
userCanAccess,
appParams,
appMeta,
appChatListDataLoading,
currentConversationId,
currentConversationItem,
appPrevChatList,
pinnedConversationList,
conversationList,
showConfigPanelBeforeChat,
newConversationInputs,
newConversationInputsRef,
handleNewConversationInputsChange,
inputsForms,
handleNewConversation,
handleStartChat,
handleChangeConversation,
handleNewConversationCompleted,
chatShouldReloadKey,
isInstalledApp,
appId,
handleFeedback,
currentChatInstanceRef,
} = useEmbeddedChatbot()
return
}
const EmbeddedChatbot = () => {
const [initialized, setInitialized] = useState(false)
const [appUnavailable, setAppUnavailable] = useState(false)
const [isUnknownReason, setIsUnknownReason] = useState(false)
useAsyncEffect(async () => {
if (!initialized) {
try {
await checkOrSetAccessToken()
}
catch (e: any) {
if (e.status === 404) {
setAppUnavailable(true)
}
else {
setIsUnknownReason(true)
setAppUnavailable(true)
}
}
setInitialized(true)
}
}, [])
if (!initialized)
return null
if (appUnavailable)
return
return
}
export default EmbeddedChatbot