index.tsx 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. import {
  2. useEffect,
  3. useState,
  4. } from 'react'
  5. import cn from 'classnames'
  6. import { useAsyncEffect } from 'ahooks'
  7. import {
  8. EmbeddedChatbotContext,
  9. useEmbeddedChatbotContext,
  10. } from './context'
  11. import { useEmbeddedChatbot } from './hooks'
  12. import { isDify } from './utils'
  13. import { useThemeContext } from './theme/theme-context'
  14. import { checkOrSetAccessToken } from '@/app/components/share/utils'
  15. import AppUnavailable from '@/app/components/base/app-unavailable'
  16. import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
  17. import Loading from '@/app/components/base/loading'
  18. import LogoHeader from '@/app/components/base/logo/logo-embeded-chat-header'
  19. import Header from '@/app/components/base/chat/embedded-chatbot/header'
  20. import ConfigPanel from '@/app/components/base/chat/embedded-chatbot/config-panel'
  21. import ChatWrapper from '@/app/components/base/chat/embedded-chatbot/chat-wrapper'
  22. const Chatbot = () => {
  23. const {
  24. isMobile,
  25. appInfoError,
  26. appInfoLoading,
  27. appData,
  28. appPrevChatList,
  29. showConfigPanelBeforeChat,
  30. appChatListDataLoading,
  31. handleNewConversation,
  32. themeBuilder,
  33. } = useEmbeddedChatbotContext()
  34. const chatReady = (!showConfigPanelBeforeChat || !!appPrevChatList.length)
  35. const customConfig = appData?.custom_config
  36. const site = appData?.site
  37. const difyIcon = <LogoHeader />
  38. useEffect(() => {
  39. themeBuilder?.buildTheme(site?.chat_color_theme, site?.chat_color_theme_inverted)
  40. if (site) {
  41. if (customConfig)
  42. document.title = `${site.title}`
  43. else
  44. document.title = `${site.title} - Powered by Dify`
  45. }
  46. }, [site, customConfig])
  47. if (appInfoLoading) {
  48. return (
  49. <Loading type='app' />
  50. )
  51. }
  52. if (appInfoError) {
  53. return (
  54. <AppUnavailable />
  55. )
  56. }
  57. return (
  58. <div>
  59. <Header
  60. isMobile={isMobile}
  61. title={site?.title || ''}
  62. customerIcon={isDify() ? difyIcon : ''}
  63. theme={themeBuilder?.theme}
  64. onCreateNewChat={handleNewConversation}
  65. />
  66. <div className='flex bg-white overflow-hidden'>
  67. <div className={cn('h-[100vh] grow flex flex-col overflow-y-auto', isMobile && '!h-[calc(100vh_-_3rem)]')}>
  68. {showConfigPanelBeforeChat && !appChatListDataLoading && !appPrevChatList.length && (
  69. <div className={cn('flex w-full items-center justify-center h-full tablet:px-4', isMobile && 'px-4')}>
  70. <ConfigPanel />
  71. </div>
  72. )}
  73. {appChatListDataLoading && chatReady && (
  74. <Loading type='app' />
  75. )}
  76. {chatReady && !appChatListDataLoading && (
  77. <ChatWrapper />
  78. )}
  79. </div>
  80. </div>
  81. </div>
  82. )
  83. }
  84. const EmbeddedChatbotWrapper = () => {
  85. const media = useBreakpoints()
  86. const isMobile = media === MediaType.mobile
  87. const themeBuilder = useThemeContext()
  88. const {
  89. appInfoError,
  90. appInfoLoading,
  91. appData,
  92. appParams,
  93. appMeta,
  94. appChatListDataLoading,
  95. currentConversationId,
  96. currentConversationItem,
  97. appPrevChatList,
  98. pinnedConversationList,
  99. conversationList,
  100. showConfigPanelBeforeChat,
  101. newConversationInputs,
  102. handleNewConversationInputsChange,
  103. inputsForms,
  104. handleNewConversation,
  105. handleStartChat,
  106. handleChangeConversation,
  107. handleNewConversationCompleted,
  108. chatShouldReloadKey,
  109. isInstalledApp,
  110. appId,
  111. handleFeedback,
  112. currentChatInstanceRef,
  113. } = useEmbeddedChatbot()
  114. return <EmbeddedChatbotContext.Provider value={{
  115. appInfoError,
  116. appInfoLoading,
  117. appData,
  118. appParams,
  119. appMeta,
  120. appChatListDataLoading,
  121. currentConversationId,
  122. currentConversationItem,
  123. appPrevChatList,
  124. pinnedConversationList,
  125. conversationList,
  126. showConfigPanelBeforeChat,
  127. newConversationInputs,
  128. handleNewConversationInputsChange,
  129. inputsForms,
  130. handleNewConversation,
  131. handleStartChat,
  132. handleChangeConversation,
  133. handleNewConversationCompleted,
  134. chatShouldReloadKey,
  135. isMobile,
  136. isInstalledApp,
  137. appId,
  138. handleFeedback,
  139. currentChatInstanceRef,
  140. themeBuilder,
  141. }}>
  142. <Chatbot />
  143. </EmbeddedChatbotContext.Provider>
  144. }
  145. const EmbeddedChatbot = () => {
  146. const [initialized, setInitialized] = useState(false)
  147. const [appUnavailable, setAppUnavailable] = useState<boolean>(false)
  148. const [isUnknownReason, setIsUnknownReason] = useState<boolean>(false)
  149. useAsyncEffect(async () => {
  150. if (!initialized) {
  151. try {
  152. await checkOrSetAccessToken()
  153. }
  154. catch (e: any) {
  155. if (e.status === 404) {
  156. setAppUnavailable(true)
  157. }
  158. else {
  159. setIsUnknownReason(true)
  160. setAppUnavailable(true)
  161. }
  162. }
  163. setInitialized(true)
  164. }
  165. }, [])
  166. if (!initialized)
  167. return null
  168. if (appUnavailable)
  169. return <AppUnavailable isUnknownReason={isUnknownReason} />
  170. return <EmbeddedChatbotWrapper />
  171. }
  172. export default EmbeddedChatbot