@memori.ai/memori-react 8.11.0 → 8.13.0

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 (243) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/dist/components/AgeVerificationModal/AgeVerificationModal.css +41 -14
  3. package/dist/components/AgeVerificationModal/AgeVerificationModal.js +2 -2
  4. package/dist/components/AgeVerificationModal/AgeVerificationModal.js.map +1 -1
  5. package/dist/components/Auth/Auth.js +36 -8
  6. package/dist/components/Auth/Auth.js.map +1 -1
  7. package/dist/components/Avatar/AvatarView/AvatarComponent/positionControls/positionControls.css +2 -2
  8. package/dist/components/Chat/Chat.css +37 -3
  9. package/dist/components/Chat/Chat.js +61 -23
  10. package/dist/components/Chat/Chat.js.map +1 -1
  11. package/dist/components/ChatBubble/ChatBubble.css +87 -15
  12. package/dist/components/ChatBubble/ChatBubble.js +129 -19
  13. package/dist/components/ChatBubble/ChatBubble.js.map +1 -1
  14. package/dist/components/ChatHistoryDrawer/ChatHistory.css +5 -1
  15. package/dist/components/ChatInputs/ChatInputs.css +293 -17
  16. package/dist/components/ChatInputs/ChatInputs.d.ts +1 -0
  17. package/dist/components/ChatInputs/ChatInputs.js +48 -27
  18. package/dist/components/ChatInputs/ChatInputs.js.map +1 -1
  19. package/dist/components/ChatTextArea/ChatTextArea.css +75 -31
  20. package/dist/components/ChatTextArea/ChatTextArea.js +47 -18
  21. package/dist/components/ChatTextArea/ChatTextArea.js.map +1 -1
  22. package/dist/components/DateSelector/DateSelector.css +125 -104
  23. package/dist/components/DateSelector/DateSelector.d.ts +1 -1
  24. package/dist/components/DateSelector/DateSelector.js +110 -52
  25. package/dist/components/DateSelector/DateSelector.js.map +1 -1
  26. package/dist/components/FilePreview/FilePreview.css +225 -146
  27. package/dist/components/FilePreview/FilePreview.d.ts +1 -2
  28. package/dist/components/FilePreview/FilePreview.js +20 -6
  29. package/dist/components/FilePreview/FilePreview.js.map +1 -1
  30. package/dist/components/Header/Header.css +2 -2
  31. package/dist/components/Header/Header.js +1 -1
  32. package/dist/components/Header/Header.js.map +1 -1
  33. package/dist/components/LoginDrawer/LoginDrawer.css +37 -5
  34. package/dist/components/LoginDrawer/LoginDrawer.d.ts +1 -2
  35. package/dist/components/LoginDrawer/LoginDrawer.js +2 -9
  36. package/dist/components/LoginDrawer/LoginDrawer.js.map +1 -1
  37. package/dist/components/MediaWidget/MediaItemWidget.js +2 -1
  38. package/dist/components/MediaWidget/MediaItemWidget.js.map +1 -1
  39. package/dist/components/MemoriArtifactSystem/components/ArtifactActions/ArtifactActions.js +1 -1
  40. package/dist/components/MemoriArtifactSystem/components/ArtifactActions/ArtifactActions.js.map +1 -1
  41. package/dist/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyButtonWithDropdown.js +1 -1
  42. package/dist/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyButtonWithDropdown.js.map +1 -1
  43. package/dist/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyMenuItem.js +3 -0
  44. package/dist/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyMenuItem.js.map +1 -1
  45. package/dist/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js +2 -2
  46. package/dist/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js.map +1 -1
  47. package/dist/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.css +16 -7
  48. package/dist/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.js +6 -4
  49. package/dist/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.js.map +1 -1
  50. package/dist/components/MemoriWidget/MemoriWidget.css +11 -2
  51. package/dist/components/MemoriWidget/MemoriWidget.js +105 -25
  52. package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
  53. package/dist/components/MicrophoneButton/MicrophoneButton.css +2 -2
  54. package/dist/components/StartPanel/StartPanel.css +8 -0
  55. package/dist/components/UploadButton/UploadButton.css +20 -17
  56. package/dist/components/UploadButton/UploadButton.js +218 -87
  57. package/dist/components/UploadButton/UploadButton.js.map +1 -1
  58. package/dist/components/UploadButton/UploadDocuments/UploadDocuments.js +14 -4
  59. package/dist/components/UploadButton/UploadDocuments/UploadDocuments.js.map +1 -1
  60. package/dist/components/UploadButton/UploadImages/UploadImages.js +143 -16
  61. package/dist/components/UploadButton/UploadImages/UploadImages.js.map +1 -1
  62. package/dist/components/layouts/chat.css +1 -1
  63. package/dist/components/ui/Drawer.css +8 -0
  64. package/dist/components/ui/Drawer.d.ts +2 -0
  65. package/dist/components/ui/Drawer.js +2 -2
  66. package/dist/components/ui/Drawer.js.map +1 -1
  67. package/dist/components/ui/Tooltip.css +49 -1
  68. package/dist/components/ui/Tooltip.d.ts +1 -1
  69. package/dist/helpers/constants.d.ts +1 -0
  70. package/dist/helpers/constants.js +2 -1
  71. package/dist/helpers/constants.js.map +1 -1
  72. package/dist/helpers/imageCompression.d.ts +7 -0
  73. package/dist/helpers/imageCompression.js +123 -0
  74. package/dist/helpers/imageCompression.js.map +1 -0
  75. package/dist/locales/de.json +13 -5
  76. package/dist/locales/en.json +17 -6
  77. package/dist/locales/es.json +13 -5
  78. package/dist/locales/fr.json +12 -5
  79. package/dist/locales/it.json +16 -6
  80. package/dist/styles.css +4 -4
  81. package/esm/components/AgeVerificationModal/AgeVerificationModal.css +41 -14
  82. package/esm/components/AgeVerificationModal/AgeVerificationModal.js +2 -2
  83. package/esm/components/AgeVerificationModal/AgeVerificationModal.js.map +1 -1
  84. package/esm/components/Auth/Auth.js +36 -8
  85. package/esm/components/Auth/Auth.js.map +1 -1
  86. package/esm/components/Avatar/AvatarView/AvatarComponent/positionControls/positionControls.css +2 -2
  87. package/esm/components/Chat/Chat.css +37 -3
  88. package/esm/components/Chat/Chat.js +61 -23
  89. package/esm/components/Chat/Chat.js.map +1 -1
  90. package/esm/components/ChatBubble/ChatBubble.css +87 -15
  91. package/esm/components/ChatBubble/ChatBubble.js +130 -20
  92. package/esm/components/ChatBubble/ChatBubble.js.map +1 -1
  93. package/esm/components/ChatHistoryDrawer/ChatHistory.css +5 -1
  94. package/esm/components/ChatInputs/ChatInputs.css +293 -17
  95. package/esm/components/ChatInputs/ChatInputs.d.ts +1 -0
  96. package/esm/components/ChatInputs/ChatInputs.js +49 -28
  97. package/esm/components/ChatInputs/ChatInputs.js.map +1 -1
  98. package/esm/components/ChatTextArea/ChatTextArea.css +75 -31
  99. package/esm/components/ChatTextArea/ChatTextArea.js +49 -20
  100. package/esm/components/ChatTextArea/ChatTextArea.js.map +1 -1
  101. package/esm/components/DateSelector/DateSelector.css +125 -104
  102. package/esm/components/DateSelector/DateSelector.d.ts +1 -1
  103. package/esm/components/DateSelector/DateSelector.js +111 -52
  104. package/esm/components/DateSelector/DateSelector.js.map +1 -1
  105. package/esm/components/FilePreview/FilePreview.css +225 -146
  106. package/esm/components/FilePreview/FilePreview.d.ts +1 -2
  107. package/esm/components/FilePreview/FilePreview.js +21 -7
  108. package/esm/components/FilePreview/FilePreview.js.map +1 -1
  109. package/esm/components/Header/Header.css +2 -2
  110. package/esm/components/Header/Header.js +1 -1
  111. package/esm/components/Header/Header.js.map +1 -1
  112. package/esm/components/LoginDrawer/LoginDrawer.css +37 -5
  113. package/esm/components/LoginDrawer/LoginDrawer.d.ts +1 -2
  114. package/esm/components/LoginDrawer/LoginDrawer.js +2 -9
  115. package/esm/components/LoginDrawer/LoginDrawer.js.map +1 -1
  116. package/esm/components/MediaWidget/MediaItemWidget.js +2 -1
  117. package/esm/components/MediaWidget/MediaItemWidget.js.map +1 -1
  118. package/esm/components/MemoriArtifactSystem/components/ArtifactActions/ArtifactActions.js +1 -1
  119. package/esm/components/MemoriArtifactSystem/components/ArtifactActions/ArtifactActions.js.map +1 -1
  120. package/esm/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyButtonWithDropdown.js +1 -1
  121. package/esm/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyButtonWithDropdown.js.map +1 -1
  122. package/esm/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyMenuItem.js +3 -0
  123. package/esm/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyMenuItem.js.map +1 -1
  124. package/esm/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js +2 -2
  125. package/esm/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js.map +1 -1
  126. package/esm/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.css +16 -7
  127. package/esm/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.js +6 -4
  128. package/esm/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.js.map +1 -1
  129. package/esm/components/MemoriWidget/MemoriWidget.css +11 -2
  130. package/esm/components/MemoriWidget/MemoriWidget.js +105 -25
  131. package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
  132. package/esm/components/MicrophoneButton/MicrophoneButton.css +2 -2
  133. package/esm/components/StartPanel/StartPanel.css +8 -0
  134. package/esm/components/UploadButton/UploadButton.css +20 -17
  135. package/esm/components/UploadButton/UploadButton.js +219 -88
  136. package/esm/components/UploadButton/UploadButton.js.map +1 -1
  137. package/esm/components/UploadButton/UploadDocuments/UploadDocuments.js +14 -4
  138. package/esm/components/UploadButton/UploadDocuments/UploadDocuments.js.map +1 -1
  139. package/esm/components/UploadButton/UploadImages/UploadImages.js +143 -16
  140. package/esm/components/UploadButton/UploadImages/UploadImages.js.map +1 -1
  141. package/esm/components/layouts/chat.css +1 -1
  142. package/esm/components/ui/Drawer.css +8 -0
  143. package/esm/components/ui/Drawer.d.ts +2 -0
  144. package/esm/components/ui/Drawer.js +2 -2
  145. package/esm/components/ui/Drawer.js.map +1 -1
  146. package/esm/components/ui/Tooltip.css +49 -1
  147. package/esm/components/ui/Tooltip.d.ts +1 -1
  148. package/esm/helpers/constants.d.ts +1 -0
  149. package/esm/helpers/constants.js +1 -0
  150. package/esm/helpers/constants.js.map +1 -1
  151. package/esm/helpers/imageCompression.d.ts +7 -0
  152. package/esm/helpers/imageCompression.js +119 -0
  153. package/esm/helpers/imageCompression.js.map +1 -0
  154. package/esm/locales/de.json +13 -5
  155. package/esm/locales/en.json +17 -6
  156. package/esm/locales/es.json +13 -5
  157. package/esm/locales/fr.json +12 -5
  158. package/esm/locales/it.json +16 -6
  159. package/esm/styles.css +4 -4
  160. package/package.json +2 -2
  161. package/src/components/AgeVerificationModal/AgeVerificationModal.css +41 -14
  162. package/src/components/AgeVerificationModal/AgeVerificationModal.tsx +3 -1
  163. package/src/components/Auth/Auth.tsx +55 -11
  164. package/src/components/Avatar/Avatar.stories.tsx +3 -0
  165. package/src/components/Avatar/AvatarView/AvatarComponent/positionControls/positionControls.css +2 -2
  166. package/src/components/Chat/Chat.css +37 -3
  167. package/src/components/Chat/Chat.stories.tsx +16 -2
  168. package/src/components/Chat/Chat.tsx +90 -21
  169. package/src/components/Chat/__snapshots__/Chat.test.tsx.snap +1752 -812
  170. package/src/components/ChatBubble/ChatBubble.css +87 -15
  171. package/src/components/ChatBubble/ChatBubble.stories.tsx +16 -2
  172. package/src/components/ChatBubble/ChatBubble.test.tsx +17 -0
  173. package/src/components/ChatBubble/ChatBubble.tsx +237 -33
  174. package/src/components/ChatBubble/__snapshots__/ChatBubble.test.tsx.snap +304 -8
  175. package/src/components/ChatHistoryDrawer/ChatHistory.css +5 -1
  176. package/src/components/ChatInputs/ChatInputs.css +293 -17
  177. package/src/components/ChatInputs/ChatInputs.tsx +156 -86
  178. package/src/components/ChatInputs/__snapshots__/ChatInputs.test.tsx.snap +430 -424
  179. package/src/components/ChatTextArea/ChatTextArea.css +75 -31
  180. package/src/components/ChatTextArea/ChatTextArea.test.tsx +1 -16
  181. package/src/components/ChatTextArea/ChatTextArea.tsx +51 -22
  182. package/src/components/ChatTextArea/__snapshots__/ChatTextArea.test.tsx.snap +9 -72
  183. package/src/components/DateSelector/DateSelector.css +125 -104
  184. package/src/components/DateSelector/DateSelector.stories.tsx +1 -1
  185. package/src/components/DateSelector/DateSelector.test.tsx +137 -23
  186. package/src/components/DateSelector/DateSelector.tsx +203 -177
  187. package/src/components/FilePreview/FilePreview.css +225 -146
  188. package/src/components/FilePreview/FilePreview.tsx +49 -36
  189. package/src/components/FilePreview/__snapshots__/FilePreview.test.tsx.snap +2 -2
  190. package/src/components/Header/Header.css +2 -2
  191. package/src/components/Header/Header.stories.tsx +5 -1
  192. package/src/components/Header/Header.tsx +1 -1
  193. package/src/components/Header/__snapshots__/Header.test.tsx.snap +1 -1
  194. package/src/components/LoginDrawer/LoginDrawer.css +37 -5
  195. package/src/components/LoginDrawer/LoginDrawer.stories.tsx +0 -1
  196. package/src/components/LoginDrawer/LoginDrawer.test.tsx +0 -1
  197. package/src/components/LoginDrawer/LoginDrawer.tsx +0 -19
  198. package/src/components/MediaWidget/MediaItemWidget.tsx +2 -1
  199. package/src/components/MemoriArtifactSystem/ArtifactDrawer.stories.tsx +996 -204
  200. package/src/components/MemoriArtifactSystem/components/ArtifactActions/ArtifactActions.tsx +2 -2
  201. package/src/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyButtonWithDropdown.tsx +1 -1
  202. package/src/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyMenuItem.tsx +3 -0
  203. package/src/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.tsx +56 -54
  204. package/src/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.css +16 -7
  205. package/src/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.tsx +12 -3
  206. package/src/components/MemoriWidget/MemoriWidget.css +11 -2
  207. package/src/components/MemoriWidget/MemoriWidget.stories.tsx +6 -3
  208. package/src/components/MemoriWidget/MemoriWidget.tsx +173 -49
  209. package/src/components/MicrophoneButton/MicrophoneButton.css +2 -2
  210. package/src/components/StartPanel/StartPanel.css +8 -0
  211. package/src/components/UploadButton/UploadButton.css +20 -17
  212. package/src/components/UploadButton/UploadButton.stories.tsx +247 -35
  213. package/src/components/UploadButton/UploadButton.tsx +280 -173
  214. package/src/components/UploadButton/UploadDocuments/UploadDocuments.tsx +19 -4
  215. package/src/components/UploadButton/UploadImages/UploadImages.tsx +196 -35
  216. package/src/components/UploadButton/__snapshots__/UploadButton.test.tsx.snap +10 -1
  217. package/src/components/layouts/FullBody/FullBody.stories.tsx +9 -10
  218. package/src/components/layouts/Totem/Totem.stories.tsx +8 -9
  219. package/src/components/layouts/ZoomedFullBody/ZoomedFullBody.stories.tsx +8 -9
  220. package/src/components/layouts/chat.css +1 -1
  221. package/src/components/layouts/layouts.stories.tsx +10 -9
  222. package/src/components/ui/Drawer.css +8 -0
  223. package/src/components/ui/Drawer.tsx +16 -12
  224. package/src/components/ui/Tooltip.css +49 -1
  225. package/src/components/ui/Tooltip.tsx +1 -1
  226. package/src/helpers/constants.ts +1 -1
  227. package/src/helpers/imageCompression.ts +230 -0
  228. package/src/index.stories.tsx +18 -0
  229. package/src/locales/de.json +13 -5
  230. package/src/locales/en.json +17 -6
  231. package/src/locales/es.json +13 -5
  232. package/src/locales/fr.json +12 -5
  233. package/src/locales/it.json +16 -6
  234. package/src/mocks/data.ts +4 -2
  235. package/src/styles.css +4 -4
  236. package/src/components/SignupForm/SignupForm.test.tsx +0 -40
  237. package/src/components/SignupForm/SignupForm.tsx +0 -457
  238. package/src/components/SignupForm/__snapshots__/SignupForm.test.tsx.snap +0 -247
  239. package/src/components/UploadMenu/UploadMenu.css +0 -47
  240. package/src/components/UploadMenu/UploadMenu.stories.tsx +0 -66
  241. package/src/components/UploadMenu/UploadMenu.test.tsx +0 -34
  242. package/src/components/UploadMenu/UploadMenu.tsx +0 -68
  243. package/src/components/UploadMenu/__snapshots__/UploadMenu.test.tsx.snap +0 -137
@@ -8,6 +8,7 @@ import memoriApiClient from '@memori.ai/memori-api-client';
8
8
  import { Asset, Medium } from '@memori.ai/memori-api-client/dist/types';
9
9
  import { useTranslation } from 'react-i18next';
10
10
  import Button from '../../ui/Button';
11
+ import { compressImage } from '../../../helpers/imageCompression';
11
12
 
12
13
  // Types
13
14
  type PreviewFile = {
@@ -74,10 +75,8 @@ const UploadImages: React.FC<UploadImagesProps> = ({
74
75
  }
75
76
  }, [isLoading, onLoadingChange]);
76
77
 
77
- // Check current image count
78
- const currentImageCount = documentPreviewFiles.filter(
79
- (file: any) => file.type === 'image'
80
- ).length;
78
+ // Check current total media count (images + documents)
79
+ const currentMediaCount = documentPreviewFiles.length;
81
80
 
82
81
  // Image upload
83
82
  const validateImageFile = (file: File): boolean => {
@@ -91,42 +90,192 @@ const UploadImages: React.FC<UploadImagesProps> = ({
91
90
  const files = Array.from(e.target.files || []);
92
91
  if (files.length === 0) return;
93
92
 
94
- // Check if adding this file would exceed the limit
95
- if (currentImageCount >= maxImages) {
93
+ // Check if adding these files would exceed the total media limit
94
+ if (currentMediaCount + files.length > maxImages) {
96
95
  onImageError?.({
97
96
  message:
98
- t('upload.maxImagesReached') ??
99
- `Maximum ${maxImages} images allowed.`,
97
+ `Maximum ${maxImages} media files allowed. You can upload ${Math.max(0, maxImages - currentMediaCount)} more file${maxImages - currentMediaCount !== 1 ? 's' : ''}.`,
100
98
  severity: 'error',
101
99
  });
102
100
  return;
103
101
  }
104
102
 
105
- const file = files[0]; // Only handle the first file
103
+ // Validate all files first
104
+ const validFiles = files.filter(file => {
105
+ if (!validateImageFile(file)) {
106
+ return false;
107
+ }
108
+ return true;
109
+ });
106
110
 
107
- if (!validateImageFile(file)) {
111
+ if (validFiles.length === 0) {
108
112
  if (imageInputRef.current) {
109
113
  imageInputRef.current.value = '';
110
114
  }
111
115
  return;
112
116
  }
113
117
 
114
- // Set file and create preview
115
- setSelectedFile(file);
116
- setFilePreview(URL.createObjectURL(file));
117
-
118
- // Set initial title as filename without extension
119
- const fileName = file.name.split('.').slice(0, -1).join('.');
120
- setImageTitle(fileName);
121
-
122
- // Show upload modal with preview
123
- setShowUploadModal(true);
118
+ // If only one file, show modal for title input
119
+ if (validFiles.length === 1) {
120
+ const file = validFiles[0];
121
+ setSelectedFile(file);
122
+ setFilePreview(URL.createObjectURL(file));
123
+
124
+ // Set initial title as filename without extension
125
+ const fileName = file.name.split('.').slice(0, -1).join('.');
126
+ setImageTitle(fileName);
127
+
128
+ // Show upload modal with preview
129
+ setShowUploadModal(true);
130
+ } else {
131
+ // For multiple files, upload them directly with default titles
132
+ await uploadMultipleImages(validFiles);
133
+ }
124
134
 
125
135
  if (imageInputRef.current) {
126
136
  imageInputRef.current.value = '';
127
137
  }
128
138
  };
129
139
 
140
+ const uploadMultipleImages = async (files: File[]) => {
141
+ setIsLoading(true);
142
+
143
+ try {
144
+ const uploadPromises = files.map(async (file) => {
145
+ // Compress image before upload
146
+ let fileToUpload = file;
147
+ try {
148
+ fileToUpload = await compressImage(file);
149
+ } catch (error) {
150
+ // If compression fails, use original file
151
+ console.warn('Image compression failed, using original file', error);
152
+ fileToUpload = file;
153
+ }
154
+
155
+ return new Promise<{
156
+ name: string;
157
+ id: string;
158
+ content: string;
159
+ type: string;
160
+ mediumID: string | undefined;
161
+ url: string;
162
+ mimeType: string;
163
+ } | null>((resolve) => {
164
+ const reader = new FileReader();
165
+
166
+ reader.onload = async (e) => {
167
+ const fileDataUrl = e.target?.result as string;
168
+ const fileId = Math.random().toString(36).substr(2, 9);
169
+ const fileName = fileToUpload.name.split('.').slice(0, -1).join('.');
170
+
171
+ if (client) {
172
+ try {
173
+ let asset: Asset;
174
+ let response;
175
+
176
+ if (authToken && backend?.uploadAsset) {
177
+ response = await backend.uploadAsset(
178
+ fileToUpload.name,
179
+ fileDataUrl,
180
+ authToken
181
+ );
182
+ } else if (memoriID && sessionID && backend?.uploadAssetUnlogged) {
183
+ response = await backend.uploadAssetUnlogged(
184
+ fileToUpload.name,
185
+ fileDataUrl,
186
+ memoriID,
187
+ sessionID
188
+ );
189
+
190
+ if (!response) {
191
+ throw new Error('Upload failed');
192
+ }
193
+ } else {
194
+ throw new Error('Missing required parameters for upload');
195
+ }
196
+
197
+ asset = response.asset;
198
+ if (response.resultCode !== 0) {
199
+ throw new Error(response.resultMessage || 'Upload failed');
200
+ }
201
+
202
+ let medium: any = null;
203
+ if (dialog?.postMediumSelectedEvent && sessionID) {
204
+ medium = await dialog.postMediumSelectedEvent(sessionID, {
205
+ url: asset.assetURL,
206
+ mimeType: asset.mimeType,
207
+ } as Medium);
208
+ }
209
+
210
+ let finalMediumID: string | undefined = undefined;
211
+ if (medium?.currentState?.currentMedia) {
212
+ const existingMediumIDs = new Set(
213
+ documentPreviewFiles.map((file: any) => file.mediumID)
214
+ );
215
+
216
+ finalMediumID = medium.currentState.currentMedia.find(
217
+ (media: any) => !existingMediumIDs.has(media.mediumID)
218
+ )?.mediumID;
219
+ }
220
+
221
+ resolve({
222
+ name: fileName,
223
+ id: fileId,
224
+ url: asset.assetURL,
225
+ content: asset.assetURL,
226
+ type: 'image',
227
+ mediumID: finalMediumID,
228
+ mimeType: asset.mimeType,
229
+ });
230
+ } catch (error) {
231
+ onImageError?.({
232
+ message: t('upload.uploadFailed') ?? 'Upload failed',
233
+ severity: 'error',
234
+ });
235
+ resolve(null);
236
+ }
237
+ } else {
238
+ onImageError?.({
239
+ message:
240
+ t('upload.apiClientNotConfigured') ??
241
+ 'API client not configured properly for media upload',
242
+ severity: 'warning',
243
+ });
244
+ resolve(null);
245
+ }
246
+ };
247
+
248
+ reader.onerror = () => {
249
+ onImageError?.({
250
+ message: t('upload.fileReadingFailed') ?? 'File reading failed',
251
+ severity: 'error',
252
+ });
253
+ resolve(null);
254
+ };
255
+
256
+ reader.readAsDataURL(fileToUpload);
257
+ });
258
+ });
259
+
260
+ const results = await Promise.all(uploadPromises);
261
+ const successfulUploads = results.filter(result => result !== null);
262
+
263
+ if (successfulUploads.length > 0) {
264
+ setDocumentPreviewFiles((prevFiles: any[]) => [
265
+ ...prevFiles,
266
+ ...successfulUploads,
267
+ ]);
268
+ }
269
+ } catch (error) {
270
+ onImageError?.({
271
+ message: t('upload.uploadFailed') ?? 'Upload failed',
272
+ severity: 'error',
273
+ });
274
+ } finally {
275
+ setIsLoading(false);
276
+ }
277
+ };
278
+
130
279
  const handleTitleSubmit = async () => {
131
280
  if (!selectedFile || !imageTitle.trim()) return;
132
281
 
@@ -134,6 +283,16 @@ const UploadImages: React.FC<UploadImagesProps> = ({
134
283
  setShowUploadModal(false);
135
284
 
136
285
  try {
286
+ // Compress image before upload
287
+ let fileToUpload = selectedFile;
288
+ try {
289
+ fileToUpload = await compressImage(selectedFile);
290
+ } catch (error) {
291
+ // If compression fails, use original file
292
+ console.warn('Image compression failed, using original file', error);
293
+ fileToUpload = selectedFile;
294
+ }
295
+
137
296
  const reader = new FileReader();
138
297
 
139
298
  reader.onload = async e => {
@@ -147,13 +306,14 @@ const UploadImages: React.FC<UploadImagesProps> = ({
147
306
 
148
307
  if (authToken && backend?.uploadAsset) {
149
308
  response = await backend.uploadAsset(
150
- selectedFile.name,
309
+ fileToUpload.name,
151
310
  fileDataUrl,
152
- authToken
311
+ authToken,
312
+ // memoriID
153
313
  );
154
314
  } else if (memoriID && sessionID && backend?.uploadAssetUnlogged) {
155
315
  response = await backend.uploadAssetUnlogged(
156
- selectedFile.name,
316
+ fileToUpload.name,
157
317
  fileDataUrl,
158
318
  memoriID,
159
319
  sessionID
@@ -240,7 +400,7 @@ const UploadImages: React.FC<UploadImagesProps> = ({
240
400
  setIsLoading(false);
241
401
  };
242
402
 
243
- reader.readAsDataURL(selectedFile);
403
+ reader.readAsDataURL(fileToUpload);
244
404
  } catch (error) {
245
405
  onImageError?.({
246
406
  message: t('upload.uploadFailed') ?? 'Upload failed',
@@ -264,10 +424,11 @@ const UploadImages: React.FC<UploadImagesProps> = ({
264
424
  ref={imageInputRef}
265
425
  type="file"
266
426
  accept=".jpg,.jpeg,.png"
427
+ multiple
267
428
  className="memori--upload-file-input"
268
429
  onChange={handleImageUpload}
269
430
  disabled={
270
- isLoading || !isMediaAccepted || currentImageCount >= maxImages
431
+ isLoading || !isMediaAccepted || currentMediaCount >= maxImages
271
432
  }
272
433
  />
273
434
 
@@ -283,7 +444,7 @@ const UploadImages: React.FC<UploadImagesProps> = ({
283
444
  )}
284
445
  onClick={() => imageInputRef.current?.click()}
285
446
  disabled={
286
- isLoading || !isMediaAccepted || currentImageCount >= maxImages
447
+ isLoading || !isMediaAccepted || currentMediaCount >= maxImages
287
448
  }
288
449
  >
289
450
  {isLoading ? (
@@ -301,7 +462,7 @@ const UploadImages: React.FC<UploadImagesProps> = ({
301
462
  className="memori--modal-preview-file"
302
463
  onClose={handleCancelUpload}
303
464
  closable
304
- title={t('upload.titleImage', { title: imageTitle })}
465
+ // title={t('upload.titleImage', { title: imageTitle })}
305
466
  // description={t('upload.imageTitleDescription')}
306
467
  >
307
468
  <div
@@ -337,20 +498,20 @@ const UploadImages: React.FC<UploadImagesProps> = ({
337
498
  style={{ width: '90%', marginBottom: '20px' }}
338
499
  className="memori--upload-title-input"
339
500
  />
340
- <div style={{ display: 'flex', gap: '10px' }}>
501
+ <div style={{ display: 'flex', gap: '10px', justifyContent: 'center', alignItems: 'center' }}>
502
+ <Button
503
+ onClick={handleCancelUpload}
504
+ className="memori-button memori-button--outline memori--upload-image"
505
+ >
506
+ {t('cancel') ?? 'Cancel'}
507
+ </Button>
341
508
  <Button
342
509
  onClick={handleTitleSubmit}
343
510
  disabled={!selectedFile || !imageTitle.trim()}
344
- className="memori-button memori-button--primary"
511
+ className="memori-button memori-button--primary memori-button--image-confirm memori--upload-image"
345
512
  >
346
513
  {t('confirm') ?? 'Confirm'}
347
514
  </Button>
348
- <Button
349
- onClick={handleCancelUpload}
350
- className="memori-button memori-button--primary"
351
- >
352
- {t('cancel') ?? 'Cancel'}
353
- </Button>
354
515
  </div>
355
516
  </div>
356
517
  </div>
@@ -5,6 +5,13 @@ exports[`renders UploadButton unchanged 1`] = `
5
5
  <div
6
6
  class="memori--unified-upload-wrapper"
7
7
  >
8
+ <input
9
+ accept=".jpg,.jpeg,.png,.pdf,.txt,.json,.xlsx,.csv,.md,.html"
10
+ class="memori--upload-file-input"
11
+ multiple=""
12
+ style="display: none;"
13
+ type="file"
14
+ />
8
15
  <button
9
16
  class="memori-button memori-button--circle memori-button--icon-only memori-share-button--button memori--conversation-button memori--unified-upload-button"
10
17
  title="upload.uploadFiles"
@@ -45,8 +52,9 @@ exports[`renders UploadButton unchanged 1`] = `
45
52
  class="memori--document-upload-wrapper"
46
53
  >
47
54
  <input
48
- accept=".pdf,.txt,.md,.json,.xlsx,.csv"
55
+ accept=".pdf,.txt,.md,.json,.xlsx,.csv,.html"
49
56
  class="memori--upload-file-input"
57
+ multiple=""
50
58
  type="file"
51
59
  />
52
60
  <button
@@ -108,6 +116,7 @@ exports[`renders UploadButton unchanged 1`] = `
108
116
  accept=".jpg,.jpeg,.png"
109
117
  class="memori--upload-file-input"
110
118
  disabled=""
119
+ multiple=""
111
120
  type="file"
112
121
  />
113
122
  <button
@@ -9,7 +9,7 @@ import { ArtifactProvider } from '../../MemoriArtifactSystem/context/ArtifactCon
9
9
 
10
10
  const meta: Meta = {
11
11
  title: 'General/Layouts/FullBody',
12
- component: (args: Props) => <Memori {...args} engineURL="https://engine.memori.ai" apiURL="https://backend.memori.ai" baseURL="https://www.aisuru.com" />,
12
+ component: (args: Props) => <Memori {...args} />,
13
13
  argTypes: {},
14
14
  parameters: {
15
15
  controls: { expanded: true },
@@ -32,14 +32,13 @@ const Template: Story<Props> = args => (
32
32
 
33
33
  const DefaultLayout = Template.bind({});
34
34
  DefaultLayout.args = {
35
- memoriName: 'Layout Storybook',
35
+ emoriName: 'Layout Storybook',
36
36
  ownerUserName: 'andrea.patini',
37
- memoriID: '157860e8-f014-43b3-a7c5-fb4a08c87025',
38
- ownerUserID: '95753bbe-9e88-4799-ae35-dc060bc11c48',
39
- tenantID: 'www.aisuru.com',
40
- engineURL: 'https://engine.memori.ai/memori/v2',
41
- apiURL: 'https://backend.memori.ai/api/v2',
42
- baseURL: 'https://www.aisuru.com',
37
+ memoriID: 'ae20fc5a-cc15-4db9-b7dd-2cd4a621b85e',
38
+ ownerUserID: '91dbc9ba-b684-4fbe-9828-b5980af6cda9',
39
+ tenantID: 'aisuru-staging.aclambda.online',
40
+ engineURL: 'https://engine-staging.memori.ai/memori/v2',
41
+ apiURL: 'https://backend-staging.memori.ai/api/v2',
43
42
  layout: 'FULL_CHAT',
44
43
  uiLang: 'IT',
45
44
  spokenLang: 'IT',
@@ -63,7 +62,7 @@ export const FullBodyWithFullBodyAvatar = Template.bind({});
63
62
  FullBodyWithFullBodyAvatar.args = {
64
63
  ...DefaultLayout.args,
65
64
  avatar3DURL:
66
- 'https://assets.memori.ai/api/v2/asset/692580d6-7b25-4ed0-84ce-82d5f4ac4270.glb#1762875775270',
65
+ 'https://assets-staging.memori.ai/api/v2/asset/c0bb0d40-aebf-4e58-bfa0-45a4d7935153.glb#1763646903757',
67
66
  integration: {
68
67
  ...baseIntegration,
69
68
  customData: JSON.stringify({
@@ -75,7 +74,7 @@ FullBodyWithFullBodyAvatar.args = {
75
74
  multilanguage: true,
76
75
  avatar: 'readyplayerme-full',
77
76
  avatarURL:
78
- 'https://assets.memori.ai/api/v2/asset/692580d6-7b25-4ed0-84ce-82d5f4ac4270.glb#1762875775270',
77
+ 'https://assets-staging.memori.ai/api/v2/asset/c0bb0d40-aebf-4e58-bfa0-45a4d7935153.glb#1763646903757',
79
78
  name: 'Layout Storybook',
80
79
  showShare: true,
81
80
  }),
@@ -32,14 +32,13 @@ const Template: Story<Props> = args => (
32
32
 
33
33
  const DefaultLayout = Template.bind({});
34
34
  DefaultLayout.args = {
35
- memoriName: 'Layout Storybook',
35
+ emoriName: 'Layout Storybook',
36
36
  ownerUserName: 'andrea.patini',
37
- memoriID: '157860e8-f014-43b3-a7c5-fb4a08c87025',
38
- ownerUserID: '95753bbe-9e88-4799-ae35-dc060bc11c48',
39
- tenantID: 'www.aisuru.com',
40
- engineURL: 'https://engine.memori.ai/memori/v2',
41
- apiURL: 'https://backend.memori.ai/api/v2',
42
- baseURL: 'https://www.aisuru.com',
37
+ memoriID: 'ae20fc5a-cc15-4db9-b7dd-2cd4a621b85e',
38
+ ownerUserID: '91dbc9ba-b684-4fbe-9828-b5980af6cda9',
39
+ tenantID: 'aisuru-staging.aclambda.online',
40
+ engineURL: 'https://engine-staging.memori.ai/memori/v2',
41
+ apiURL: 'https://backend-staging.memori.ai/api/v2',
43
42
  layout: 'FULL_CHAT',
44
43
  uiLang: 'IT',
45
44
  spokenLang: 'IT',
@@ -63,7 +62,7 @@ export const TotemWithFullBodyAvatar = Template.bind({});
63
62
  TotemWithFullBodyAvatar.args = {
64
63
  ...DefaultLayout.args,
65
64
  avatar3DURL:
66
- 'https://assets.memori.ai/api/v2/asset/692580d6-7b25-4ed0-84ce-82d5f4ac4270.glb#1762875775270',
65
+ 'https://assets-staging.memori.ai/api/v2/asset/c0bb0d40-aebf-4e58-bfa0-45a4d7935153.glb#1763646903757',
67
66
  integration: {
68
67
  ...baseIntegration,
69
68
  customData: JSON.stringify({
@@ -75,7 +74,7 @@ TotemWithFullBodyAvatar.args = {
75
74
  multilanguage: true,
76
75
  avatar: 'readyplayerme-full',
77
76
  avatarURL:
78
- 'https://assets.memori.ai/api/v2/asset/692580d6-7b25-4ed0-84ce-82d5f4ac4270.glb#1762875775270',
77
+ 'https://assets-staging.memori.ai/api/v2/asset/c0bb0d40-aebf-4e58-bfa0-45a4d7935153.glb#1763646903757',
79
78
  name: 'Layout Storybook',
80
79
  showShare: true,
81
80
  }),
@@ -32,14 +32,13 @@ const Template: Story<Props> = args => (
32
32
 
33
33
  const DefaultLayout = Template.bind({});
34
34
  DefaultLayout.args = {
35
- memoriName: 'Layout Storybook',
35
+ emoriName: 'Layout Storybook',
36
36
  ownerUserName: 'andrea.patini',
37
- memoriID: '157860e8-f014-43b3-a7c5-fb4a08c87025',
38
- ownerUserID: '95753bbe-9e88-4799-ae35-dc060bc11c48',
39
- tenantID: 'www.aisuru.com',
40
- engineURL: 'https://engine.memori.ai/memori/v2',
41
- apiURL: 'https://backend.memori.ai/api/v2',
42
- baseURL: 'https://www.aisuru.com',
37
+ memoriID: 'ae20fc5a-cc15-4db9-b7dd-2cd4a621b85e',
38
+ ownerUserID: '91dbc9ba-b684-4fbe-9828-b5980af6cda9',
39
+ tenantID: 'aisuru-staging.aclambda.online',
40
+ engineURL: 'https://engine-staging.memori.ai/memori/v2',
41
+ apiURL: 'https://backend-staging.memori.ai/api/v2',
43
42
  layout: 'FULL_CHAT',
44
43
  uiLang: 'IT',
45
44
  spokenLang: 'IT',
@@ -63,7 +62,7 @@ export const ZoomedFullBodyWithFullBodyAvatar = Template.bind({});
63
62
  ZoomedFullBodyWithFullBodyAvatar.args = {
64
63
  ...DefaultLayout.args,
65
64
  avatar3DURL:
66
- 'https://assets.memori.ai/api/v2/asset/692580d6-7b25-4ed0-84ce-82d5f4ac4270.glb#1762875775270',
65
+ 'https://assets-staging.memori.ai/api/v2/asset/c0bb0d40-aebf-4e58-bfa0-45a4d7935153.glb#1763646903757',
67
66
  integration: {
68
67
  ...baseIntegration,
69
68
  customData: JSON.stringify({
@@ -75,7 +74,7 @@ ZoomedFullBodyWithFullBodyAvatar.args = {
75
74
  multilanguage: true,
76
75
  avatar: 'readyplayerme-full',
77
76
  avatarURL:
78
- 'https://assets.memori.ai/api/v2/asset/692580d6-7b25-4ed0-84ce-82d5f4ac4270.glb#1762875775270',
77
+ 'https://assets-staging.memori.ai/api/v2/asset/c0bb0d40-aebf-4e58-bfa0-45a4d7935153.glb#1763646903757',
79
78
  name: 'Layout Storybook',
80
79
  showShare: true,
81
80
  }),
@@ -68,7 +68,7 @@
68
68
  height: 100%;
69
69
  max-height: 100%;
70
70
  flex: 1;
71
- padding-bottom: 3rem;
71
+ /* padding-bottom: 1.5rem; */
72
72
  transition: all 0.05s ease-in-out;
73
73
  }
74
74
 
@@ -11,7 +11,7 @@ import { ArtifactProvider } from '../MemoriArtifactSystem/context/ArtifactContex
11
11
 
12
12
  const meta: Meta = {
13
13
  title: 'General/Layouts',
14
- component: (args: Props) => <Memori {...args} engineURL="https://engine.memori.ai" apiURL="https://backend.memori.ai" baseURL="https://www.aisuru.com" />,
14
+ component: (args: Props) => <Memori {...args} />,
15
15
  argTypes: {},
16
16
  parameters: {
17
17
  controls: { expanded: true },
@@ -36,19 +36,20 @@ const DefaultLayout = Template.bind({});
36
36
  DefaultLayout.args = {
37
37
  memoriName: 'Layout Storybook',
38
38
  ownerUserName: 'andrea.patini',
39
- memoriID: '157860e8-f014-43b3-a7c5-fb4a08c87025',
40
- ownerUserID: '95753bbe-9e88-4799-ae35-dc060bc11c48',
41
- tenantID: 'www.aisuru.com',
42
- engineURL: 'https://engine.memori.ai/memori/v2',
43
- apiURL: 'https://backend.memori.ai/api/v2',
44
- baseURL: 'https://www.aisuru.com',
45
- layout: 'FULL_CHAT',
39
+ memoriID: 'ae20fc5a-cc15-4db9-b7dd-2cd4a621b85e',
40
+ ownerUserID: '91dbc9ba-b684-4fbe-9828-b5980af6cda9',
41
+ tenantID: 'aisuru-staging.aclambda.online',
42
+ engineURL: 'https://engine-staging.memori.ai/memori/v2',
43
+ apiURL: 'https://backend-staging.memori.ai/api/v2',
44
+ layout: 'FULLPAGE',
46
45
  uiLang: 'IT',
47
46
  spokenLang: 'IT',
48
47
  integrationID: '0b1256c1-530c-4e67-aef8-36667c8887bb',
49
48
  autoStart: false,
50
49
  sessionID: '' as string | undefined,
51
-
50
+ showUpload: true,
51
+ showReasoning: false,
52
+ showLogin: true
52
53
  };
53
54
 
54
55
 
@@ -188,6 +188,14 @@ h2.memori-drawer--title {
188
188
  transition-duration: 200ms;
189
189
  }
190
190
 
191
+ .duration-400 {
192
+ transition-duration: 400ms;
193
+ }
194
+
195
+ .duration-500 {
196
+ transition-duration: 500ms;
197
+ }
198
+
191
199
  .opacity-0 {
192
200
  opacity: 0;
193
201
  }
@@ -40,13 +40,15 @@ export interface Props {
40
40
  confirmDialogMessage?: string;
41
41
  showBackdrop?: boolean;
42
42
  preventBackdropClose?: boolean;
43
+ enterDuration?: string;
44
+ leaveDuration?: string;
43
45
  }
44
46
 
45
47
  const Drawer: FC<Props> = ({
46
48
  title,
47
49
  open = false,
48
50
  data,
49
- onClose = () => {},
51
+ onClose = () => { },
50
52
  children,
51
53
  width = '80%',
52
54
  footer,
@@ -63,6 +65,8 @@ const Drawer: FC<Props> = ({
63
65
  confirmDialogTitle,
64
66
  confirmDialogMessage,
65
67
  preventBackdropClose = false,
68
+ enterDuration = 'duration-300',
69
+ leaveDuration = 'duration-200',
66
70
  }: Props) => {
67
71
  const [originalData, setOriginalData] = useState<any>(null);
68
72
  const [confirmDialogOpen, setConfirmDialogOpen] = useState(false);
@@ -120,19 +124,19 @@ const Drawer: FC<Props> = ({
120
124
  <Transition appear show={open} as={React.Fragment}>
121
125
  <Dialog
122
126
  open={open}
123
- onClose={preventBackdropClose ? () => {} : handleClose}
127
+ onClose={preventBackdropClose ? () => { } : handleClose}
124
128
  className={cx('memori-drawer', className)}
125
129
  >
126
130
  {showBackdrop && (
127
131
  <Transition.Child
128
- as={React.Fragment}
129
- enter="ease-out duration-300"
130
- enterFrom="opacity-0"
131
- enterTo="opacity-100"
132
- leave="ease-in duration-200"
133
- leaveFrom="opacity-100"
134
- leaveTo="opacity-0"
135
- >
132
+ as={React.Fragment}
133
+ enter="ease-out duration-300"
134
+ enterFrom="opacity-0"
135
+ enterTo="opacity-100"
136
+ leave="ease-in duration-200"
137
+ leaveFrom="opacity-100"
138
+ leaveTo="opacity-0"
139
+ >
136
140
  <div className="memori-drawer--backdrop" />
137
141
  </Transition.Child>
138
142
  )}
@@ -141,10 +145,10 @@ const Drawer: FC<Props> = ({
141
145
  <Transition.Child
142
146
  static
143
147
  as={React.Fragment}
144
- enter="ease-out duration-300"
148
+ enter={`ease-out ${enterDuration}`}
145
149
  enterFrom={animated ? 'max-w-0 opacity-0' : 'opacity-0'}
146
150
  enterTo="max-w-80 opacity-100"
147
- leave="ease-in duration-200"
151
+ leave={`ease-in ${leaveDuration}`}
148
152
  leaveFrom="max-w-80 opacity-100"
149
153
  leaveTo={animated ? 'max-w-0 opacity-0' : 'opacity-0'}
150
154
  >