index.tsx 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. import type { FC } from 'react'
  2. import {
  3. useEffect,
  4. useState,
  5. } from 'react'
  6. import { useAsyncEffect } from 'ahooks'
  7. import { useThemeContext } from '../embedded-chatbot/theme/theme-context'
  8. import {
  9. ChatWithHistoryContext,
  10. useChatWithHistoryContext,
  11. } from './context'
  12. import { useChatWithHistory } from './hooks'
  13. import Sidebar from './sidebar'
  14. import HeaderInMobile from './header-in-mobile'
  15. import ConfigPanel from './config-panel'
  16. import ChatWrapper from './chat-wrapper'
  17. import type { InstalledApp } from '@/models/explore'
  18. import Loading from '@/app/components/base/loading'
  19. import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
  20. import { checkOrSetAccessToken } from '@/app/components/share/utils'
  21. import AppUnavailable from '@/app/components/base/app-unavailable'
  22. type ChatWithHistoryProps = {
  23. className?: string
  24. }
  25. const ChatWithHistory: FC<ChatWithHistoryProps> = ({
  26. className,
  27. }) => {
  28. const {
  29. appInfoError,
  30. appData,
  31. appInfoLoading,
  32. appPrevChatList,
  33. showConfigPanelBeforeChat,
  34. appChatListDataLoading,
  35. chatShouldReloadKey,
  36. isMobile,
  37. themeBuilder,
  38. } = useChatWithHistoryContext()
  39. const chatReady = (!showConfigPanelBeforeChat || !!appPrevChatList.length)
  40. const customConfig = appData?.custom_config
  41. const site = appData?.site
  42. useEffect(() => {
  43. themeBuilder?.buildTheme(site?.chat_color_theme, site?.chat_color_theme_inverted)
  44. if (site) {
  45. if (customConfig)
  46. document.title = `${site.title}`
  47. else
  48. document.title = `${site.title} - Powered by Dify`
  49. }
  50. }, [site, customConfig, themeBuilder])
  51. if (appInfoLoading) {
  52. return (
  53. <Loading type='app' />
  54. )
  55. }
  56. if (appInfoError) {
  57. return (
  58. <AppUnavailable />
  59. )
  60. }
  61. return (
  62. <div className={`h-full flex bg-white ${className} ${isMobile && 'flex-col'}`}>
  63. {
  64. !isMobile && (
  65. <Sidebar />
  66. )
  67. }
  68. {
  69. isMobile && (
  70. <HeaderInMobile />
  71. )
  72. }
  73. <div className={`grow overflow-hidden ${showConfigPanelBeforeChat && !appPrevChatList.length && 'flex items-center justify-center'}`}>
  74. {
  75. showConfigPanelBeforeChat && !appChatListDataLoading && !appPrevChatList.length && (
  76. <div className={`flex w-full items-center justify-center h-full ${isMobile && 'px-4'}`}>
  77. <ConfigPanel />
  78. </div>
  79. )
  80. }
  81. {
  82. appChatListDataLoading && chatReady && (
  83. <Loading type='app' />
  84. )
  85. }
  86. {
  87. chatReady && !appChatListDataLoading && (
  88. <ChatWrapper key={chatShouldReloadKey} />
  89. )
  90. }
  91. </div>
  92. </div>
  93. )
  94. }
  95. export type ChatWithHistoryWrapProps = {
  96. installedAppInfo?: InstalledApp
  97. className?: string
  98. }
  99. const ChatWithHistoryWrap: FC<ChatWithHistoryWrapProps> = ({
  100. installedAppInfo,
  101. className,
  102. }) => {
  103. const media = useBreakpoints()
  104. const isMobile = media === MediaType.mobile
  105. const themeBuilder = useThemeContext()
  106. const {
  107. appInfoError,
  108. appInfoLoading,
  109. appData,
  110. appParams,
  111. appMeta,
  112. appChatListDataLoading,
  113. currentConversationId,
  114. currentConversationItem,
  115. appPrevChatList,
  116. pinnedConversationList,
  117. conversationList,
  118. showConfigPanelBeforeChat,
  119. newConversationInputs,
  120. newConversationInputsRef,
  121. handleNewConversationInputsChange,
  122. inputsForms,
  123. handleNewConversation,
  124. handleStartChat,
  125. handleChangeConversation,
  126. handlePinConversation,
  127. handleUnpinConversation,
  128. handleDeleteConversation,
  129. conversationRenaming,
  130. handleRenameConversation,
  131. handleNewConversationCompleted,
  132. chatShouldReloadKey,
  133. isInstalledApp,
  134. appId,
  135. handleFeedback,
  136. currentChatInstanceRef,
  137. } = useChatWithHistory(installedAppInfo)
  138. return (
  139. <ChatWithHistoryContext.Provider value={{
  140. appInfoError,
  141. appInfoLoading,
  142. appData,
  143. appParams,
  144. appMeta,
  145. appChatListDataLoading,
  146. currentConversationId,
  147. currentConversationItem,
  148. appPrevChatList,
  149. pinnedConversationList,
  150. conversationList,
  151. showConfigPanelBeforeChat,
  152. newConversationInputs,
  153. newConversationInputsRef,
  154. handleNewConversationInputsChange,
  155. inputsForms,
  156. handleNewConversation,
  157. handleStartChat,
  158. handleChangeConversation,
  159. handlePinConversation,
  160. handleUnpinConversation,
  161. handleDeleteConversation,
  162. conversationRenaming,
  163. handleRenameConversation,
  164. handleNewConversationCompleted,
  165. chatShouldReloadKey,
  166. isMobile,
  167. isInstalledApp,
  168. appId,
  169. handleFeedback,
  170. currentChatInstanceRef,
  171. themeBuilder,
  172. }}>
  173. <ChatWithHistory className={className} />
  174. </ChatWithHistoryContext.Provider>
  175. )
  176. }
  177. const ChatWithHistoryWrapWithCheckToken: FC<ChatWithHistoryWrapProps> = ({
  178. installedAppInfo,
  179. className,
  180. }) => {
  181. const [initialized, setInitialized] = useState(false)
  182. const [appUnavailable, setAppUnavailable] = useState<boolean>(false)
  183. const [isUnknownReason, setIsUnknownReason] = useState<boolean>(false)
  184. useAsyncEffect(async () => {
  185. if (!initialized) {
  186. if (!installedAppInfo) {
  187. try {
  188. await checkOrSetAccessToken()
  189. }
  190. catch (e: any) {
  191. if (e.status === 404) {
  192. setAppUnavailable(true)
  193. }
  194. else {
  195. setIsUnknownReason(true)
  196. setAppUnavailable(true)
  197. }
  198. }
  199. }
  200. setInitialized(true)
  201. }
  202. }, [])
  203. if (!initialized)
  204. return null
  205. if (appUnavailable)
  206. return <AppUnavailable isUnknownReason={isUnknownReason} />
  207. return (
  208. <ChatWithHistoryWrap
  209. installedAppInfo={installedAppInfo}
  210. className={className}
  211. />
  212. )
  213. }
  214. export default ChatWithHistoryWrapWithCheckToken