index.tsx 4.7 KB

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