index.tsx 4.6 KB

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