@memori.ai/memori-react 7.28.1 → 7.29.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (287) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/dist/components/AccountForm/AccountForm.d.ts +1 -0
  3. package/dist/components/AgeVerificationModal/AgeVerificationModal.d.ts +1 -0
  4. package/dist/components/AttachmentLinkModal/AttachmentLinkModal.d.ts +1 -0
  5. package/dist/components/Auth/Auth.d.ts +1 -0
  6. package/dist/components/Avatar/AvatarView/AvatarComponent/Shadow/DynamicShadow.d.ts +1 -0
  7. package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.d.ts +1 -0
  8. package/dist/components/Avatar/AvatarView/AvatarComponent/components/controllers/AnimationController.d.ts +38 -0
  9. package/dist/components/Avatar/AvatarView/AvatarComponent/components/controllers/AnimationController.js +181 -0
  10. package/dist/components/Avatar/AvatarView/AvatarComponent/components/controllers/AnimationController.js.map +1 -0
  11. package/dist/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.d.ts +1 -0
  12. package/dist/components/Avatar/AvatarView/AvatarComponent/components/loader.d.ts +1 -0
  13. package/dist/components/Blob/Blob.d.ts +1 -0
  14. package/dist/components/BlockedMemoriBadge/BlockedMemoriBadge.d.ts +1 -0
  15. package/dist/components/Chat/Chat.d.ts +1 -0
  16. package/dist/components/Chat/Chat.js +5 -3
  17. package/dist/components/Chat/Chat.js.map +1 -1
  18. package/dist/components/ChatBubble/VirtualizedContent/VirtualizedContent.d.ts +7 -0
  19. package/dist/components/ChatBubble/VirtualizedContent/VirtualizedContent.js +69 -0
  20. package/dist/components/ChatBubble/VirtualizedContent/VirtualizedContent.js.map +1 -0
  21. package/dist/components/ChatHistoryDrawer/ChatHistory.css +324 -0
  22. package/dist/components/ChatHistoryDrawer/ChatHistory.d.ts +15 -0
  23. package/dist/components/ChatHistoryDrawer/ChatHistory.js +109 -0
  24. package/dist/components/ChatHistoryDrawer/ChatHistory.js.map +1 -0
  25. package/dist/components/CompletionProviderStatus/CompletionProviderStatus.d.ts +1 -0
  26. package/dist/components/CustomGLBModelViewer/ModelViewer.d.ts +1 -0
  27. package/dist/components/ExpertsDrawer/ExpertsDrawer.d.ts +1 -0
  28. package/dist/components/FeedbackButtons/FeedbackButtons.d.ts +1 -0
  29. package/dist/components/FilePreview/FilePreview.d.ts +1 -0
  30. package/dist/components/Header/Header.d.ts +2 -0
  31. package/dist/components/Header/Header.js +3 -2
  32. package/dist/components/Header/Header.js.map +1 -1
  33. package/dist/components/KnownFacts/KnownFacts.d.ts +1 -0
  34. package/dist/components/LoginDrawer/LoginDrawer.d.ts +1 -0
  35. package/dist/components/MemoriWidget/MemoriWidget.d.ts +2 -1
  36. package/dist/components/MemoriWidget/MemoriWidget.js +173 -21
  37. package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
  38. package/dist/components/MicrophoneButton/MicrophoneButton.d.ts +1 -0
  39. package/dist/components/PositionDrawer/PositionDrawer.d.ts +1 -0
  40. package/dist/components/PoweredBy/PoweredBy.d.ts +1 -0
  41. package/dist/components/SettingsDrawer/SettingsDrawer.d.ts +1 -0
  42. package/dist/components/SignupForm/SignupForm.d.ts +1 -0
  43. package/dist/components/Snippet/Snippet.d.ts +1 -0
  44. package/dist/components/StartPanel/StartPanel.css +20 -21
  45. package/dist/components/StartPanel/StartPanel.js.map +1 -1
  46. package/dist/components/Typing/Typing.d.ts +1 -0
  47. package/dist/components/VenueWidget/VenueWidget.css +7 -0
  48. package/dist/components/VenueWidget/VenueWidget.d.ts +1 -0
  49. package/dist/components/VenueWidget/VenueWidget.js +1 -1
  50. package/dist/components/VenueWidget/VenueWidget.js.map +1 -1
  51. package/dist/components/WhyThisAnswer/WhyThisAnswer.d.ts +1 -0
  52. package/dist/components/icons/AI.d.ts +1 -0
  53. package/dist/components/icons/Alert.d.ts +1 -0
  54. package/dist/components/icons/Bug.d.ts +1 -0
  55. package/dist/components/icons/Chat.d.ts +6 -0
  56. package/dist/components/icons/Chat.js +6 -0
  57. package/dist/components/icons/Chat.js.map +1 -0
  58. package/dist/components/icons/ChevronLeft.d.ts +1 -0
  59. package/dist/components/icons/ChevronRight.d.ts +1 -0
  60. package/dist/components/icons/Clear.d.ts +1 -0
  61. package/dist/components/icons/Close.d.ts +1 -0
  62. package/dist/components/icons/Code.d.ts +1 -0
  63. package/dist/components/icons/Copy.d.ts +1 -0
  64. package/dist/components/icons/DeepThought.d.ts +1 -0
  65. package/dist/components/icons/Delete.d.ts +1 -0
  66. package/dist/components/icons/Download.d.ts +1 -0
  67. package/dist/components/icons/Edit.d.ts +1 -0
  68. package/dist/components/icons/Expand.d.ts +1 -0
  69. package/dist/components/icons/Eye.d.ts +1 -0
  70. package/dist/components/icons/EyeInvisible.d.ts +1 -0
  71. package/dist/components/icons/Facebook.d.ts +1 -0
  72. package/dist/components/icons/Feedback.d.ts +1 -0
  73. package/dist/components/icons/File.d.ts +1 -0
  74. package/dist/components/icons/FileExcel.d.ts +1 -0
  75. package/dist/components/icons/FilePdf.d.ts +1 -0
  76. package/dist/components/icons/FileWord.d.ts +1 -0
  77. package/dist/components/icons/Fullscreen.d.ts +1 -0
  78. package/dist/components/icons/FullscreenExit.d.ts +1 -0
  79. package/dist/components/icons/Group.d.ts +1 -0
  80. package/dist/components/icons/History.d.ts +7 -0
  81. package/dist/components/icons/History.js +6 -0
  82. package/dist/components/icons/History.js.map +1 -0
  83. package/dist/components/icons/Info.d.ts +1 -0
  84. package/dist/components/icons/Link.d.ts +1 -0
  85. package/dist/components/icons/Linkedin.d.ts +1 -0
  86. package/dist/components/icons/Loading.d.ts +1 -0
  87. package/dist/components/icons/Mail.d.ts +1 -0
  88. package/dist/components/icons/MapMarker.d.ts +1 -0
  89. package/dist/components/icons/Message.d.ts +1 -0
  90. package/dist/components/icons/Microphone.d.ts +1 -0
  91. package/dist/components/icons/Minus.d.ts +1 -0
  92. package/dist/components/icons/MinusCircle.d.ts +1 -0
  93. package/dist/components/icons/PaperClip.d.ts +1 -0
  94. package/dist/components/icons/Picture.d.ts +1 -0
  95. package/dist/components/icons/Plus.d.ts +1 -0
  96. package/dist/components/icons/QuestionHelp.d.ts +1 -0
  97. package/dist/components/icons/Refresh.d.ts +1 -0
  98. package/dist/components/icons/SelectIcon.d.ts +1 -0
  99. package/dist/components/icons/Send.d.ts +1 -0
  100. package/dist/components/icons/Setting.d.ts +1 -0
  101. package/dist/components/icons/Share.d.ts +1 -0
  102. package/dist/components/icons/Sound.d.ts +1 -0
  103. package/dist/components/icons/SoundDeactivated.d.ts +1 -0
  104. package/dist/components/icons/Telegram.d.ts +1 -0
  105. package/dist/components/icons/ThumbDown.d.ts +1 -0
  106. package/dist/components/icons/ThumbUp.d.ts +1 -0
  107. package/dist/components/icons/Translation.d.ts +1 -0
  108. package/dist/components/icons/Twitter.d.ts +1 -0
  109. package/dist/components/icons/User.d.ts +1 -0
  110. package/dist/components/icons/Warning.d.ts +1 -0
  111. package/dist/components/icons/WhatsApp.d.ts +1 -0
  112. package/dist/components/ui/Card.css +4 -0
  113. package/dist/components/ui/Card.js +3 -2
  114. package/dist/components/ui/Card.js.map +1 -1
  115. package/dist/components/ui/Select.d.ts +1 -0
  116. package/dist/helpers/message.js +1 -4
  117. package/dist/helpers/message.js.map +1 -1
  118. package/dist/helpers/utils.d.ts +1 -0
  119. package/dist/helpers/utils.js +18 -1
  120. package/dist/helpers/utils.js.map +1 -1
  121. package/dist/index.d.ts +1 -0
  122. package/dist/index.js +2 -2
  123. package/dist/index.js.map +1 -1
  124. package/dist/locales/de.json +24 -17
  125. package/dist/locales/en.json +12 -5
  126. package/dist/locales/es.json +18 -11
  127. package/dist/locales/fr.json +49 -31
  128. package/dist/locales/it.json +17 -6
  129. package/dist/styles.css +1 -0
  130. package/esm/components/AccountForm/AccountForm.d.ts +1 -0
  131. package/esm/components/AgeVerificationModal/AgeVerificationModal.d.ts +1 -0
  132. package/esm/components/AttachmentLinkModal/AttachmentLinkModal.d.ts +1 -0
  133. package/esm/components/Auth/Auth.d.ts +1 -0
  134. package/esm/components/Avatar/AvatarView/AvatarComponent/Shadow/DynamicShadow.d.ts +1 -0
  135. package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.d.ts +1 -0
  136. package/esm/components/Avatar/AvatarView/AvatarComponent/components/controllers/AnimationController.d.ts +38 -0
  137. package/esm/components/Avatar/AvatarView/AvatarComponent/components/controllers/AnimationController.js +177 -0
  138. package/esm/components/Avatar/AvatarView/AvatarComponent/components/controllers/AnimationController.js.map +1 -0
  139. package/esm/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.d.ts +1 -0
  140. package/esm/components/Avatar/AvatarView/AvatarComponent/components/loader.d.ts +1 -0
  141. package/esm/components/Blob/Blob.d.ts +1 -0
  142. package/esm/components/BlockedMemoriBadge/BlockedMemoriBadge.d.ts +1 -0
  143. package/esm/components/Chat/Chat.d.ts +1 -0
  144. package/esm/components/Chat/Chat.js +5 -3
  145. package/esm/components/Chat/Chat.js.map +1 -1
  146. package/esm/components/ChatBubble/VirtualizedContent/VirtualizedContent.d.ts +7 -0
  147. package/esm/components/ChatBubble/VirtualizedContent/VirtualizedContent.js +67 -0
  148. package/esm/components/ChatBubble/VirtualizedContent/VirtualizedContent.js.map +1 -0
  149. package/esm/components/ChatHistoryDrawer/ChatHistory.css +324 -0
  150. package/esm/components/ChatHistoryDrawer/ChatHistory.d.ts +15 -0
  151. package/esm/components/ChatHistoryDrawer/ChatHistory.js +106 -0
  152. package/esm/components/ChatHistoryDrawer/ChatHistory.js.map +1 -0
  153. package/esm/components/CompletionProviderStatus/CompletionProviderStatus.d.ts +1 -0
  154. package/esm/components/CustomGLBModelViewer/ModelViewer.d.ts +1 -0
  155. package/esm/components/ExpertsDrawer/ExpertsDrawer.d.ts +1 -0
  156. package/esm/components/FeedbackButtons/FeedbackButtons.d.ts +1 -0
  157. package/esm/components/FilePreview/FilePreview.d.ts +1 -0
  158. package/esm/components/Header/Header.d.ts +2 -0
  159. package/esm/components/Header/Header.js +3 -2
  160. package/esm/components/Header/Header.js.map +1 -1
  161. package/esm/components/KnownFacts/KnownFacts.d.ts +1 -0
  162. package/esm/components/LoginDrawer/LoginDrawer.d.ts +1 -0
  163. package/esm/components/MemoriWidget/MemoriWidget.d.ts +2 -1
  164. package/esm/components/MemoriWidget/MemoriWidget.js +173 -21
  165. package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
  166. package/esm/components/MicrophoneButton/MicrophoneButton.d.ts +1 -0
  167. package/esm/components/PositionDrawer/PositionDrawer.d.ts +1 -0
  168. package/esm/components/PoweredBy/PoweredBy.d.ts +1 -0
  169. package/esm/components/SettingsDrawer/SettingsDrawer.d.ts +1 -0
  170. package/esm/components/SignupForm/SignupForm.d.ts +1 -0
  171. package/esm/components/Snippet/Snippet.d.ts +1 -0
  172. package/esm/components/StartPanel/StartPanel.css +20 -21
  173. package/esm/components/StartPanel/StartPanel.js.map +1 -1
  174. package/esm/components/Typing/Typing.d.ts +1 -0
  175. package/esm/components/VenueWidget/VenueWidget.css +7 -0
  176. package/esm/components/VenueWidget/VenueWidget.d.ts +1 -0
  177. package/esm/components/VenueWidget/VenueWidget.js +1 -1
  178. package/esm/components/VenueWidget/VenueWidget.js.map +1 -1
  179. package/esm/components/WhyThisAnswer/WhyThisAnswer.d.ts +1 -0
  180. package/esm/components/icons/AI.d.ts +1 -0
  181. package/esm/components/icons/Alert.d.ts +1 -0
  182. package/esm/components/icons/Bug.d.ts +1 -0
  183. package/esm/components/icons/Chat.d.ts +6 -0
  184. package/esm/components/icons/Chat.js +4 -0
  185. package/esm/components/icons/Chat.js.map +1 -0
  186. package/esm/components/icons/ChevronLeft.d.ts +1 -0
  187. package/esm/components/icons/ChevronRight.d.ts +1 -0
  188. package/esm/components/icons/Clear.d.ts +1 -0
  189. package/esm/components/icons/Close.d.ts +1 -0
  190. package/esm/components/icons/Code.d.ts +1 -0
  191. package/esm/components/icons/Copy.d.ts +1 -0
  192. package/esm/components/icons/DeepThought.d.ts +1 -0
  193. package/esm/components/icons/Delete.d.ts +1 -0
  194. package/esm/components/icons/Download.d.ts +1 -0
  195. package/esm/components/icons/Edit.d.ts +1 -0
  196. package/esm/components/icons/Expand.d.ts +1 -0
  197. package/esm/components/icons/Eye.d.ts +1 -0
  198. package/esm/components/icons/EyeInvisible.d.ts +1 -0
  199. package/esm/components/icons/Facebook.d.ts +1 -0
  200. package/esm/components/icons/Feedback.d.ts +1 -0
  201. package/esm/components/icons/File.d.ts +1 -0
  202. package/esm/components/icons/FileExcel.d.ts +1 -0
  203. package/esm/components/icons/FilePdf.d.ts +1 -0
  204. package/esm/components/icons/FileWord.d.ts +1 -0
  205. package/esm/components/icons/Fullscreen.d.ts +1 -0
  206. package/esm/components/icons/FullscreenExit.d.ts +1 -0
  207. package/esm/components/icons/Group.d.ts +1 -0
  208. package/esm/components/icons/History.d.ts +7 -0
  209. package/esm/components/icons/History.js +4 -0
  210. package/esm/components/icons/History.js.map +1 -0
  211. package/esm/components/icons/Info.d.ts +1 -0
  212. package/esm/components/icons/Link.d.ts +1 -0
  213. package/esm/components/icons/Linkedin.d.ts +1 -0
  214. package/esm/components/icons/Loading.d.ts +1 -0
  215. package/esm/components/icons/Mail.d.ts +1 -0
  216. package/esm/components/icons/MapMarker.d.ts +1 -0
  217. package/esm/components/icons/Message.d.ts +1 -0
  218. package/esm/components/icons/Microphone.d.ts +1 -0
  219. package/esm/components/icons/Minus.d.ts +1 -0
  220. package/esm/components/icons/MinusCircle.d.ts +1 -0
  221. package/esm/components/icons/PaperClip.d.ts +1 -0
  222. package/esm/components/icons/Picture.d.ts +1 -0
  223. package/esm/components/icons/Plus.d.ts +1 -0
  224. package/esm/components/icons/QuestionHelp.d.ts +1 -0
  225. package/esm/components/icons/Refresh.d.ts +1 -0
  226. package/esm/components/icons/SelectIcon.d.ts +1 -0
  227. package/esm/components/icons/Send.d.ts +1 -0
  228. package/esm/components/icons/Setting.d.ts +1 -0
  229. package/esm/components/icons/Share.d.ts +1 -0
  230. package/esm/components/icons/Sound.d.ts +1 -0
  231. package/esm/components/icons/SoundDeactivated.d.ts +1 -0
  232. package/esm/components/icons/Telegram.d.ts +1 -0
  233. package/esm/components/icons/ThumbDown.d.ts +1 -0
  234. package/esm/components/icons/ThumbUp.d.ts +1 -0
  235. package/esm/components/icons/Translation.d.ts +1 -0
  236. package/esm/components/icons/Twitter.d.ts +1 -0
  237. package/esm/components/icons/User.d.ts +1 -0
  238. package/esm/components/icons/Warning.d.ts +1 -0
  239. package/esm/components/icons/WhatsApp.d.ts +1 -0
  240. package/esm/components/ui/Card.css +4 -0
  241. package/esm/components/ui/Card.js +3 -2
  242. package/esm/components/ui/Card.js.map +1 -1
  243. package/esm/components/ui/Select.d.ts +1 -0
  244. package/esm/helpers/message.js +1 -4
  245. package/esm/helpers/message.js.map +1 -1
  246. package/esm/helpers/utils.d.ts +1 -0
  247. package/esm/helpers/utils.js +16 -0
  248. package/esm/helpers/utils.js.map +1 -1
  249. package/esm/index.d.ts +1 -0
  250. package/esm/index.js +2 -2
  251. package/esm/index.js.map +1 -1
  252. package/esm/locales/de.json +24 -17
  253. package/esm/locales/en.json +12 -5
  254. package/esm/locales/es.json +18 -11
  255. package/esm/locales/fr.json +49 -31
  256. package/esm/locales/it.json +17 -6
  257. package/esm/styles.css +1 -0
  258. package/package.json +1 -1
  259. package/src/components/Chat/Chat.tsx +5 -2
  260. package/src/components/ChatHistoryDrawer/ChatHistory.css +324 -0
  261. package/src/components/ChatHistoryDrawer/ChatHistory.scss +41 -0
  262. package/src/components/ChatHistoryDrawer/ChatHistory.stories.tsx +290 -0
  263. package/src/components/ChatHistoryDrawer/ChatHistory.test.tsx +91 -0
  264. package/src/components/ChatHistoryDrawer/ChatHistory.tsx +393 -0
  265. package/src/components/ChatHistoryDrawer/__snapshots__/ChatHistory.test.tsx.snap +27 -0
  266. package/src/components/Header/Header.test.tsx +16 -1
  267. package/src/components/Header/Header.tsx +18 -0
  268. package/src/components/Header/__snapshots__/Header.test.tsx.snap +140 -0
  269. package/src/components/MemoriWidget/MemoriWidget.tsx +249 -16
  270. package/src/components/StartPanel/StartPanel.css +20 -21
  271. package/src/components/StartPanel/StartPanel.tsx +1 -0
  272. package/src/components/VenueWidget/VenueWidget.css +7 -0
  273. package/src/components/VenueWidget/VenueWidget.tsx +4 -4
  274. package/src/components/icons/Chat.tsx +30 -0
  275. package/src/components/icons/History.tsx +33 -0
  276. package/src/components/ui/Card.css +4 -0
  277. package/src/components/ui/Card.tsx +2 -1
  278. package/src/helpers/message.ts +0 -2
  279. package/src/helpers/utils.ts +23 -0
  280. package/src/index.stories.tsx +36 -9
  281. package/src/index.tsx +3 -0
  282. package/src/locales/de.json +24 -17
  283. package/src/locales/en.json +12 -5
  284. package/src/locales/es.json +18 -11
  285. package/src/locales/fr.json +49 -31
  286. package/src/locales/it.json +17 -6
  287. package/src/styles.css +1 -0
@@ -0,0 +1,91 @@
1
+ import React from 'react';
2
+ import { render } from '@testing-library/react';
3
+ import ChatHistoryDrawer from './ChatHistory';
4
+ import memoriApiClient from '@memori.ai/memori-api-client';
5
+ import { memori } from '../../mocks/data';
6
+
7
+ // Mock IntersectionObserver
8
+ beforeEach(() => {
9
+ window.IntersectionObserver = jest.fn().mockImplementation(() => ({
10
+ observe: jest.fn(),
11
+ unobserve: jest.fn(),
12
+ disconnect: jest.fn(),
13
+ takeRecords: jest.fn(),
14
+ root: null,
15
+ rootMargin: '',
16
+ thresholds: [],
17
+ }));
18
+ });
19
+
20
+ // Mock the translation hook
21
+ jest.mock('react-i18next', () => ({
22
+ useTranslation: () => ({
23
+ t: (key: string) => key,
24
+ }),
25
+ }));
26
+
27
+ const client = memoriApiClient();
28
+
29
+ it('renders ChatHistoryDrawer unchanged', () => {
30
+ const { container } = render(
31
+ <ChatHistoryDrawer
32
+ open={true}
33
+ onClose={jest.fn()}
34
+ apiClient={client}
35
+ sessionId="test-session"
36
+ memori={memori}
37
+ resumeSession={jest.fn()}
38
+ baseUrl="https://www.aisuru.com"
39
+ apiUrl="https://backend.memori.ai"
40
+ />
41
+ );
42
+ expect(container).toMatchSnapshot();
43
+ });
44
+
45
+ it('renders ChatHistoryDrawer with chat logs unchanged', () => {
46
+ const { container } = render(
47
+ <ChatHistoryDrawer
48
+ open={true}
49
+ onClose={jest.fn()}
50
+ apiClient={client}
51
+ sessionId="test-session"
52
+ memori={memori}
53
+ resumeSession={jest.fn()}
54
+ baseUrl="https://www.aisuru.com"
55
+ apiUrl="https://backend.memori.ai"
56
+ />
57
+ );
58
+ expect(container).toMatchSnapshot();
59
+ });
60
+
61
+ it('renders ChatHistoryDrawer with selected chat log unchanged', () => {
62
+ const { container } = render(
63
+ <ChatHistoryDrawer
64
+ open={true}
65
+ onClose={jest.fn()}
66
+ apiClient={client}
67
+ sessionId="test-session"
68
+ memori={memori}
69
+ resumeSession={jest.fn()}
70
+ baseUrl="https://www.aisuru.com"
71
+ apiUrl="https://backend.memori.ai"
72
+ />
73
+ );
74
+ expect(container).toMatchSnapshot();
75
+ });
76
+
77
+ it('renders ChatHistoryDrawer closed unchanged', () => {
78
+ const { container } = render(
79
+ <ChatHistoryDrawer
80
+ open={false}
81
+ onClose={jest.fn()}
82
+ apiClient={client}
83
+ sessionId="test-session"
84
+ memori={memori}
85
+ resumeSession={jest.fn()}
86
+ baseUrl="https://www.aisuru.com"
87
+ apiUrl="https://backend.memori.ai"
88
+ />
89
+ );
90
+ expect(container).toMatchSnapshot();
91
+ });
@@ -0,0 +1,393 @@
1
+ import Drawer from '../ui/Drawer';
2
+ import { useTranslation } from 'react-i18next';
3
+ import { Props as WidgetProps } from '../MemoriWidget/MemoriWidget';
4
+ import memoriApiClient from '@memori.ai/memori-api-client';
5
+ import { useEffect, useMemo, useState, useCallback, ChangeEvent } from 'react';
6
+ import {
7
+ ChatLog,
8
+ ChatLogLine,
9
+ User,
10
+ Memori,
11
+ Medium,
12
+ DialogState,
13
+ EventLog,
14
+ } from '@memori.ai/memori-api-client/dist/types';
15
+ import Card from '../ui/Card';
16
+ import ChatBubble from '../ChatBubble/ChatBubble';
17
+ import Button from '../ui/Button';
18
+ import ChatRound from '../icons/Chat';
19
+ import { truncateMessage } from '../../helpers/utils';
20
+ import { Dialog, Transition } from '@headlessui/react';
21
+ import debounce from 'lodash/debounce';
22
+ import Chat from '../Chat/Chat';
23
+ import Spin from '../ui/Spin';
24
+
25
+ export interface Props {
26
+ open: boolean;
27
+ onClose: () => void;
28
+ apiClient: ReturnType<typeof memoriApiClient>;
29
+ sessionId: string;
30
+ memori: Memori;
31
+ resumeSession: (chatLog: ChatLog) => void;
32
+ baseUrl: string;
33
+ apiUrl: string;
34
+ }
35
+
36
+ const ITEMS_PER_PAGE = 8;
37
+ const DEBOUNCE_DELAY = 300;
38
+
39
+ const ChatHistoryDrawer = ({
40
+ open,
41
+ onClose,
42
+ apiClient,
43
+ sessionId,
44
+ memori,
45
+ resumeSession,
46
+ baseUrl,
47
+ apiUrl,
48
+ }: Props) => {
49
+ const { t } = useTranslation();
50
+ const { getChatLogsByUser, getSessionChatLogs } = apiClient.chatLogs;
51
+
52
+ const [chatLogs, setChatLogs] = useState<ChatLog[]>([]);
53
+ const [selectedChatLog, setSelectedChatLog] = useState<ChatLog | null>(null);
54
+ const [currentPage, setCurrentPage] = useState(1);
55
+ const [searchText, setSearchText] = useState('');
56
+ const [isLoading, setIsLoading] = useState(false);
57
+ const [error, setError] = useState<string | null>(null);
58
+ const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('desc');
59
+
60
+ const fetchChatLogs = useCallback(async () => {
61
+ setIsLoading(true);
62
+ setError(null);
63
+ try {
64
+ const res = await getChatLogsByUser(sessionId);
65
+ setChatLogs(res.chatLogs.sort((a, b) => {
66
+ const dateA = Math.max(...a.lines.map(l => new Date(l.timestamp).getTime()));
67
+ const dateB = Math.max(...b.lines.map(l => new Date(l.timestamp).getTime()));
68
+ return sortOrder === 'desc' ? dateB - dateA : dateA - dateB;
69
+ }));
70
+ } catch (err) {
71
+ setError(t('errorFetchingSession') || 'Error loading chat history');
72
+ console.error('Error fetching chat logs:', err);
73
+ } finally {
74
+ setIsLoading(false);
75
+ }
76
+ }, [sessionId, sortOrder]);
77
+
78
+ useEffect(() => {
79
+ if (open) fetchChatLogs();
80
+ }, [open, fetchChatLogs]);
81
+
82
+ const debouncedSearch = useMemo(
83
+ () => debounce((value: string) => setSearchText(value), DEBOUNCE_DELAY),
84
+ []
85
+ );
86
+
87
+ const filteredChatLogs = useMemo(() => {
88
+ return chatLogs.filter(c =>
89
+ c.lines.some(l => l.text.toLowerCase().includes(searchText.toLowerCase())) &&
90
+ c.lines.length > 1
91
+ );
92
+ }, [chatLogs, searchText]);
93
+
94
+ const totalPages = Math.ceil(filteredChatLogs.length / ITEMS_PER_PAGE);
95
+
96
+ const paginatedChatLogs = useMemo(() => {
97
+ const startIndex = (currentPage - 1) * ITEMS_PER_PAGE;
98
+ return filteredChatLogs.slice(startIndex, startIndex + ITEMS_PER_PAGE);
99
+ }, [filteredChatLogs, currentPage]);
100
+
101
+ const handleResumeChat = async () => {
102
+ if (selectedChatLog) {
103
+ resumeSession(selectedChatLog);
104
+ onClose();
105
+ }
106
+ };
107
+
108
+ const formatDate = (timestamp: string) => {
109
+ return new Intl.DateTimeFormat(navigator.language, {
110
+ dateStyle: 'medium',
111
+ timeStyle: 'short',
112
+ }).format(new Date(timestamp));
113
+ };
114
+
115
+ const renderContent = () => {
116
+ if (isLoading) {
117
+ return (
118
+ <div className="memori-chat-history-drawer--loading">
119
+ <Spin spinning={true} primary={true} className="memori-chat-history-drawer--loading--spinner" />
120
+ <p className="memori-chat-history-drawer--loading--text">{t('write_and_speak.loadingChatHistory') || 'Loading chat history...'}</p>
121
+ </div>
122
+ );
123
+ }
124
+
125
+ if (error) {
126
+ return (
127
+ <div className="memori-chat-history-drawer--error">
128
+ <p>{error}</p>
129
+ </div>
130
+ );
131
+ }
132
+
133
+ if (!chatLogs.length) {
134
+ return (
135
+ <div className="memori-chat-history-drawer--empty">
136
+ <ChatRound className="memori-chat-history-drawer--empty--icon" />
137
+ <p className="memori-chat-history-drawer--empty--text">{t('write_and_speak.noChatHistoryAvailable') || 'No chat history available'}</p>
138
+ </div>
139
+ );
140
+ }
141
+
142
+ if (filteredChatLogs.length === 0) {
143
+ return (
144
+ <div className="memori-chat-history-drawer--no-results">
145
+ <p>{t('write_and_speak.noResultsFound', { searchText: searchText || '' }) || 'No results found'}</p>
146
+ </div>
147
+ );
148
+ }
149
+
150
+
151
+ return (
152
+ <>
153
+ <ul className="memori-chat-history-drawer--list">
154
+ {paginatedChatLogs.map((chatLog: ChatLog) => {
155
+ const lastMessageDate = Math.max(
156
+ ...chatLog.lines.map(line => new Date(line.timestamp).getTime())
157
+ );
158
+
159
+ return (
160
+ <Card
161
+ hoverable
162
+ onClick={async () => {
163
+ if (selectedChatLog?.chatLogID === chatLog.chatLogID) {
164
+ setSelectedChatLog(null);
165
+ return;
166
+ }
167
+ // Check for chat-reference tag in the first line
168
+ // const firstMessage = chatLog.lines[1]?.text;
169
+ // const chatReferenceMatch = firstMessage?.match(/<chat-reference session-id="([^"]+)" event-log-id="([^"]+)"><\/chat-reference>/);
170
+ // if (chatReferenceMatch) {
171
+ // const [_, refSessionId, refChatLogId] = chatReferenceMatch;
172
+ // try {
173
+ // const res = await getSessionChatLogs(refSessionId, refSessionId);
174
+ // const prevChatLog = res.chatLogs.find((c: ChatLog) => c.chatLogID === refChatLogId);
175
+ // if (prevChatLog) {
176
+ // setSelectedChatLog({
177
+ // ...chatLog,
178
+ // lines: [
179
+ // ...prevChatLog.lines,
180
+ // ...chatLog.lines
181
+ // ]
182
+ // });
183
+ // return;
184
+ // }
185
+ // } catch (e) {
186
+ // console.error('Error fetching referenced chat log:', e);
187
+ // }
188
+ // }
189
+ setSelectedChatLog(chatLog);
190
+ }}
191
+ key={chatLog.chatLogID}
192
+ className={`memori-chat-history-drawer--card ${
193
+ selectedChatLog?.chatLogID === chatLog.chatLogID ? 'memori-chat-history-drawer--card--selected' : ''
194
+ }`}
195
+ >
196
+ <>
197
+ <div className="memori-chat-history-drawer--card--header">
198
+ <div className="memori-chat-history-drawer--card--header--content">
199
+ <div className="memori-chat-history-drawer--card--header--icon-wrapper">
200
+ <ChatRound className="memori-chat-history-drawer--card--header--icon" />
201
+ </div>
202
+ <div className="memori-chat-history-drawer--card--header--info">
203
+ <div className="memori-chat-history-drawer--card--header--title-wrapper">
204
+ <Dialog.Title as="h3" className="memori-chat-history-drawer--card--header--title">
205
+ {'Chat-' + chatLog.chatLogID.substring(0, 4)}
206
+ </Dialog.Title>
207
+ {chatLog.boardOfExperts && (
208
+ <div className="memori-chat-history-drawer--card--header--badge">
209
+ BOE
210
+ </div>
211
+ )}
212
+ </div>
213
+ <div className="memori-chat-history-drawer--card--header--meta">
214
+ {chatLog.lines.some(line => line.media && line.media.filter(m => m.mimeType !== 'text/html' && m.mimeType !== 'text/plain').length > 0) && (
215
+ <span className="memori-chat-history-drawer--card--header--meta--messages">
216
+ <svg className="memori-chat-history-drawer--card--header--meta--icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
217
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
218
+ </svg>
219
+ {chatLog.lines.reduce((acc, line) => acc + (line.media?.filter(m => m.mimeType !== 'text/html' && m.mimeType !== 'text/plain').length || 0), 0)}
220
+ </span>
221
+ )}
222
+ <span className="memori-chat-history-drawer--card--header--meta--messages">
223
+ <svg className="memori-chat-history-drawer--card--header--meta--icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
224
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z" />
225
+ </svg>
226
+ {chatLog.lines.length}
227
+ </span>
228
+ <time className="memori-chat-history-drawer--card--header--meta--time" dateTime={new Date(lastMessageDate).toISOString()}>
229
+ <svg className="memori-chat-history-drawer--card--header--meta--icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
230
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
231
+ </svg>
232
+ {formatDate(new Date(lastMessageDate).toISOString())}
233
+ </time>
234
+ </div>
235
+ </div>
236
+ </div>
237
+ </div>
238
+
239
+ {selectedChatLog?.chatLogID === chatLog.chatLogID && (
240
+ <div className="memori-chat-history-drawer--card--content">
241
+ <div className="memori-chat-history-drawer--card--content--messages">
242
+ <Chat
243
+ key={`${chatLog.lines[0].text}-${chatLog.lines[0].timestamp}`}
244
+ baseUrl={baseUrl}
245
+ apiUrl={apiUrl}
246
+ memoriTyping={false}
247
+ showTypingText={false}
248
+ showAIicon={true}
249
+ showTranslationOriginal={false}
250
+ showWhyThisAnswer={false}
251
+ showCopyButton={false}
252
+ showInputs={false}
253
+ history={chatLog.lines.map(line => ({
254
+ text: truncateMessage(line.text),
255
+ contextVars: line.contextVars,
256
+ media: line.media as Medium[],
257
+ fromUser: line.inbound,
258
+ timestamp: line.timestamp,
259
+ }))}
260
+ memori={memori}
261
+ sessionID={sessionId}
262
+ setDialogState={() => {}}
263
+ pushMessage={() => {}}
264
+ simulateUserPrompt={() => {}}
265
+ setSendOnEnter={() => {}}
266
+ attachmentsMenuOpen={undefined}
267
+ setAttachmentsMenuOpen={() => {}}
268
+ userMessage={''}
269
+ onChangeUserMessage={() => {}}
270
+ sendMessage={() => {}}
271
+ startListening={() => {}}
272
+ stopListening={() => {}}
273
+ resetTranscript={() => {}}
274
+ listening={false}
275
+ setEnableFocusChatInput={() => {}}
276
+ stopAudio={() => {}}
277
+ isHistoryView={true}
278
+ />
279
+ </div>
280
+
281
+ <div className="memori-chat-history-drawer--card--content--actions">
282
+ <Button
283
+ className="memori-chat-history-drawer--card--content--resume-button"
284
+ primary
285
+ onClick={handleResumeChat}
286
+ >
287
+ <div className="memori-chat-history-drawer--card--content--resume-button--content">
288
+ <ChatRound className="memori-chat-history-drawer--card--content--resume-button--icon" />
289
+ <span className="memori-chat-history-drawer--card--content--resume-button--text">
290
+ {t('write_and_speak.resumeButton') || 'Resume chat'}
291
+ </span>
292
+ </div>
293
+ </Button>
294
+ </div>
295
+ </div>
296
+ )}
297
+ </>
298
+ </Card>
299
+ );
300
+ })}
301
+ </ul>
302
+
303
+ {totalPages > 1 && (
304
+ <div className="memori-chat-history-drawer--pagination">
305
+ <Button
306
+ primary
307
+ onClick={() => setCurrentPage(p => Math.max(1, p - 1))}
308
+ disabled={currentPage === 1}
309
+ className="memori-chat-history-drawer--pagination--button"
310
+ >
311
+ {t('previous') || 'Previous'}
312
+ </Button>
313
+ <span className="memori-chat-history-drawer--pagination--info">
314
+ {t('write_and_speak.page', { current: currentPage, total: totalPages })}
315
+ </span>
316
+ <Button
317
+ primary
318
+ onClick={() => setCurrentPage(p => Math.min(totalPages, p + 1))}
319
+ disabled={currentPage === totalPages}
320
+ className="memori-chat-history-drawer--pagination--button"
321
+ >
322
+ {t('next') || 'Next'}
323
+ </Button>
324
+ </div>
325
+ )}
326
+ </>
327
+ );
328
+ };
329
+
330
+ return (
331
+ <Drawer
332
+ className="memori-chat-history-drawer"
333
+ open={open}
334
+ onClose={onClose}
335
+ title={t('write_and_speak.chatHistory') || 'Chat History'}
336
+ description={t('write_and_speak.chatHistoryDescription')}
337
+ >
338
+ <div className="memori-chat-history-drawer--content">
339
+ <div className="memori-chat-history-drawer--toolbar">
340
+ <div className="memori-chat-history-drawer--toolbar--search">
341
+ <input
342
+ type="search"
343
+ className="memori-chat-history-drawer--toolbar--search--input"
344
+ placeholder={t('write_and_speak.searchInChatHistory') || 'Search in chat history...'}
345
+ onChange={(e: ChangeEvent<HTMLInputElement>) => debouncedSearch(e.target.value)}
346
+ />
347
+ <span className="memori-chat-history-drawer--toolbar--search--icon">
348
+ <svg fill="none" viewBox="0 0 24 24" stroke="currentColor">
349
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
350
+ </svg>
351
+ </span>
352
+ </div>
353
+ <div className="memori-chat-history-drawer--toolbar--actions">
354
+ <Button
355
+ onClick={() => {
356
+ setSortOrder(order => order === 'asc' ? 'desc' : 'asc');
357
+ setCurrentPage(1);
358
+ }}
359
+ className="memori-chat-history-drawer--toolbar--sort-button"
360
+ >
361
+ {sortOrder === 'desc' ? t('write_and_speak.latestFirst') : t('write_and_speak.oldestFirst')}
362
+ </Button>
363
+ {/* <Button
364
+ onClick={() => {
365
+ if (selectedChatLog) {
366
+ const chatText = selectedChatLog.lines
367
+ .map(line => `${line.inbound ? 'User' : 'AI'}: ${line.text}`)
368
+ .join('\n\n');
369
+ const blob = new Blob([chatText], { type: 'text/plain' });
370
+ const url = URL.createObjectURL(blob);
371
+ const a = document.createElement('a');
372
+ a.href = url;
373
+ a.download = `chat-${selectedChatLog.chatLogID.substring(0, 4)}.txt`;
374
+ document.body.appendChild(a);
375
+ a.click();
376
+ document.body.removeChild(a);
377
+ URL.revokeObjectURL(url);
378
+ }
379
+ }}
380
+ disabled={!selectedChatLog}
381
+ className="memori-chat-history-drawer--toolbar--export-button"
382
+ >
383
+ {t('write_and_speak.exportChat') || 'Export Chat'}
384
+ </Button> */}
385
+ </div>
386
+ </div>
387
+ {renderContent()}
388
+ </div>
389
+ </Drawer>
390
+ );
391
+ };
392
+
393
+ export default ChatHistoryDrawer;
@@ -0,0 +1,27 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`renders ChatHistoryDrawer closed unchanged 1`] = `<div />`;
4
+
5
+ exports[`renders ChatHistoryDrawer unchanged 1`] = `
6
+ <div>
7
+ <div
8
+ style="position: fixed; top: 1px; left: 1px; width: 1px; height: 0px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0px, 0px, 0px, 0px); white-space: nowrap; border-width: 0px; display: none;"
9
+ />
10
+ </div>
11
+ `;
12
+
13
+ exports[`renders ChatHistoryDrawer with chat logs unchanged 1`] = `
14
+ <div>
15
+ <div
16
+ style="position: fixed; top: 1px; left: 1px; width: 1px; height: 0px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0px, 0px, 0px, 0px); white-space: nowrap; border-width: 0px; display: none;"
17
+ />
18
+ </div>
19
+ `;
20
+
21
+ exports[`renders ChatHistoryDrawer with selected chat log unchanged 1`] = `
22
+ <div>
23
+ <div
24
+ style="position: fixed; top: 1px; left: 1px; width: 1px; height: 0px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0px, 0px, 0px, 0px); white-space: nowrap; border-width: 0px; display: none;"
25
+ />
26
+ </div>
27
+ `;
@@ -8,6 +8,7 @@ it('renders Header unchanged', () => {
8
8
  <Header
9
9
  memori={memori}
10
10
  history={history}
11
+ setShowChatHistoryDrawer={jest.fn()}
11
12
  setShowPositionDrawer={jest.fn()}
12
13
  setShowSettingsDrawer={jest.fn()}
13
14
  setShowKnownFactsDrawer={jest.fn()}
@@ -37,6 +38,7 @@ it('renders Header with position unchanged', () => {
37
38
  longitude: 13.404954,
38
39
  }}
39
40
  history={history}
41
+ setShowChatHistoryDrawer={jest.fn()}
40
42
  setShowPositionDrawer={jest.fn()}
41
43
  setShowSettingsDrawer={jest.fn()}
42
44
  setShowKnownFactsDrawer={jest.fn()}
@@ -69,6 +71,7 @@ it('renders Header with speaker muted unchanged', () => {
69
71
  showSettings={false}
70
72
  clearHistory={jest.fn()}
71
73
  setShowLoginDrawer={jest.fn()}
74
+ setShowChatHistoryDrawer={jest.fn()}
72
75
  />
73
76
  );
74
77
  expect(container).toMatchSnapshot();
@@ -91,6 +94,7 @@ it('renders Header with audio disabled unchanged', () => {
91
94
  showSettings={false}
92
95
  clearHistory={jest.fn()}
93
96
  setShowLoginDrawer={jest.fn()}
97
+ setShowChatHistoryDrawer={jest.fn()}
94
98
  />
95
99
  );
96
100
  expect(container).toMatchSnapshot();
@@ -112,6 +116,7 @@ it('renders Header with share button unchanged', () => {
112
116
  showSettings={false}
113
117
  clearHistory={jest.fn()}
114
118
  setShowLoginDrawer={jest.fn()}
119
+ setShowChatHistoryDrawer={jest.fn()}
115
120
  />
116
121
  );
117
122
  expect(container).toMatchSnapshot();
@@ -133,6 +138,7 @@ it('renders Header with settings button unchanged', () => {
133
138
  showSettings={true}
134
139
  clearHistory={jest.fn()}
135
140
  setShowLoginDrawer={jest.fn()}
141
+ setShowChatHistoryDrawer={jest.fn()}
136
142
  />
137
143
  );
138
144
  expect(container).toMatchSnapshot();
@@ -152,9 +158,10 @@ it('renders Header with clear button unchanged', () => {
152
158
  hasUserActivatedSpeak={false}
153
159
  showShare={false}
154
160
  showSettings={false}
155
- showClear
161
+ showClear={true}
156
162
  clearHistory={jest.fn()}
157
163
  setShowLoginDrawer={jest.fn()}
164
+ setShowChatHistoryDrawer={jest.fn()}
158
165
  />
159
166
  );
160
167
  expect(container).toMatchSnapshot();
@@ -176,6 +183,7 @@ it('renders Header with user activated speak unchanged', () => {
176
183
  showSettings={false}
177
184
  clearHistory={jest.fn()}
178
185
  setShowLoginDrawer={jest.fn()}
186
+ setShowChatHistoryDrawer={jest.fn()}
179
187
  />
180
188
  );
181
189
  expect(container).toMatchSnapshot();
@@ -193,6 +201,7 @@ it('renders Header with deep thought unlogged unchanged', () => {
193
201
  setShowSettingsDrawer={jest.fn()}
194
202
  setShowKnownFactsDrawer={jest.fn()}
195
203
  setShowExpertsDrawer={jest.fn()}
204
+ setShowChatHistoryDrawer={jest.fn()}
196
205
  speakerMuted={false}
197
206
  setSpeakerMuted={jest.fn()}
198
207
  hasUserActivatedSpeak={false}
@@ -221,6 +230,7 @@ it('renders Header with deep thought logged but without permission flag unchange
221
230
  speakerMuted={false}
222
231
  setSpeakerMuted={jest.fn()}
223
232
  hasUserActivatedSpeak={false}
233
+
224
234
  showShare={false}
225
235
  showSettings={false}
226
236
  clearHistory={jest.fn()}
@@ -230,6 +240,7 @@ it('renders Header with deep thought logged but without permission flag unchange
230
240
  pAndCUAccepted: false,
231
241
  }}
232
242
  setShowLoginDrawer={jest.fn()}
243
+ setShowChatHistoryDrawer={jest.fn()}
233
244
  />
234
245
  );
235
246
  expect(container).toMatchSnapshot();
@@ -259,6 +270,7 @@ it('renders Header with deep thought logged with permission flag unchanged', ()
259
270
  pAndCUAccepted: true,
260
271
  }}
261
272
  setShowLoginDrawer={jest.fn()}
273
+ setShowChatHistoryDrawer={jest.fn()}
262
274
  />
263
275
  );
264
276
  expect(container).toMatchSnapshot();
@@ -285,6 +297,7 @@ it('renders Header with deep thought and session open unchanged', () => {
285
297
  sessionID="1234"
286
298
  loginToken="abcd"
287
299
  setShowLoginDrawer={jest.fn()}
300
+ setShowChatHistoryDrawer={jest.fn()}
288
301
  />
289
302
  );
290
303
  expect(container).toMatchSnapshot();
@@ -310,6 +323,7 @@ it('renders Header for board of experts unchanged', () => {
310
323
  clearHistory={jest.fn()}
311
324
  loginToken="abcd"
312
325
  setShowLoginDrawer={jest.fn()}
326
+ setShowChatHistoryDrawer={jest.fn()}
313
327
  />
314
328
  );
315
329
  expect(container).toMatchSnapshot();
@@ -336,6 +350,7 @@ it('renders Header for board of experts with session open unchanged', () => {
336
350
  sessionID="1234"
337
351
  loginToken="abcd"
338
352
  setShowLoginDrawer={jest.fn()}
353
+ setShowChatHistoryDrawer={jest.fn()}
339
354
  />
340
355
  );
341
356
  expect(container).toMatchSnapshot();
@@ -22,6 +22,9 @@ import Clear from '../icons/Clear';
22
22
  import DeepThought from '../icons/DeepThought';
23
23
  import Group from '../icons/Group';
24
24
  import UserIcon from '../icons/User';
25
+ import History from '../icons/History';
26
+ import Tooltip from '../ui/Tooltip';
27
+ import { Popover } from '@headlessui/react';
25
28
 
26
29
  export interface Props {
27
30
  className?: string;
@@ -31,6 +34,7 @@ export interface Props {
31
34
  position?: Venue;
32
35
  setShowPositionDrawer: (show: boolean) => void;
33
36
  setShowSettingsDrawer: (show: boolean) => void;
37
+ setShowChatHistoryDrawer: (show: boolean) => void;
34
38
  setShowKnownFactsDrawer: (show: boolean) => void;
35
39
  setShowExpertsDrawer: (show: boolean) => void;
36
40
  enableAudio?: boolean;
@@ -39,6 +43,7 @@ export interface Props {
39
43
  hasUserActivatedSpeak?: boolean;
40
44
  showShare?: boolean;
41
45
  showSettings?: boolean;
46
+ showChatHistory?: boolean;
42
47
  showSpeaker?: boolean;
43
48
  showReload?: boolean;
44
49
  showClear?: boolean;
@@ -59,6 +64,7 @@ const Header: React.FC<Props> = ({
59
64
  position,
60
65
  setShowPositionDrawer,
61
66
  setShowSettingsDrawer,
67
+ setShowChatHistoryDrawer,
62
68
  setShowKnownFactsDrawer,
63
69
  setShowExpertsDrawer,
64
70
  enableAudio = true,
@@ -76,6 +82,7 @@ const Header: React.FC<Props> = ({
76
82
  loginToken,
77
83
  user,
78
84
  sessionID,
85
+ showChatHistory = true,
79
86
  fullScreenHandler,
80
87
  }) => {
81
88
  const { t } = useTranslation();
@@ -128,6 +135,17 @@ const Header: React.FC<Props> = ({
128
135
  onClick={clearHistory}
129
136
  />
130
137
  )}
138
+ {showChatHistory && !!loginToken && (
139
+ <Button
140
+ primary
141
+ disabled={!loginToken || history.length === 0}
142
+ shape="circle"
143
+ className="memori-header--button memori-header--button--chat-history"
144
+ title={t('write_and_speak.chatHistory') || 'Chat history'}
145
+ icon={<History disabled={!loginToken || history.length === 0} />}
146
+ onClick={() => setShowChatHistoryDrawer(true)}
147
+ />
148
+ )}
131
149
  {fullScreenAvailable && (
132
150
  <Button
133
151
  primary