@memori.ai/memori-react 2.18.8 → 2.19.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 (47) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +1 -0
  3. package/dist/components/Chat/Chat.d.ts +3 -1
  4. package/dist/components/Chat/Chat.js +2 -2
  5. package/dist/components/Chat/Chat.js.map +1 -1
  6. package/dist/components/Chat/Chat.test.js +12 -0
  7. package/dist/components/Chat/Chat.test.js.map +1 -1
  8. package/dist/components/ChatBubble/ChatBubble.d.ts +4 -1
  9. package/dist/components/ChatBubble/ChatBubble.js +4 -2
  10. package/dist/components/ChatBubble/ChatBubble.js.map +1 -1
  11. package/dist/components/ChatBubble/ChatBubble.test.js +27 -0
  12. package/dist/components/ChatBubble/ChatBubble.test.js.map +1 -1
  13. package/dist/components/MemoriWidget/MemoriWidget.d.ts +2 -1
  14. package/dist/components/MemoriWidget/MemoriWidget.js +39 -26
  15. package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
  16. package/dist/index.d.ts +1 -0
  17. package/dist/index.js +3 -2
  18. package/dist/index.js.map +1 -1
  19. package/esm/components/Chat/Chat.d.ts +3 -1
  20. package/esm/components/Chat/Chat.js +2 -2
  21. package/esm/components/Chat/Chat.js.map +1 -1
  22. package/esm/components/Chat/Chat.test.js +12 -0
  23. package/esm/components/Chat/Chat.test.js.map +1 -1
  24. package/esm/components/ChatBubble/ChatBubble.d.ts +4 -1
  25. package/esm/components/ChatBubble/ChatBubble.js +5 -3
  26. package/esm/components/ChatBubble/ChatBubble.js.map +1 -1
  27. package/esm/components/ChatBubble/ChatBubble.test.js +27 -0
  28. package/esm/components/ChatBubble/ChatBubble.test.js.map +1 -1
  29. package/esm/components/MemoriWidget/MemoriWidget.d.ts +2 -1
  30. package/esm/components/MemoriWidget/MemoriWidget.js +39 -26
  31. package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
  32. package/esm/index.d.ts +1 -0
  33. package/esm/index.js +3 -2
  34. package/esm/index.js.map +1 -1
  35. package/package.json +2 -2
  36. package/src/components/Chat/Chat.stories.tsx +51 -0
  37. package/src/components/Chat/Chat.test.tsx +96 -0
  38. package/src/components/Chat/Chat.tsx +7 -0
  39. package/src/components/Chat/__snapshots__/Chat.test.tsx.snap +1329 -252
  40. package/src/components/ChatBubble/ChatBubble.stories.tsx +57 -0
  41. package/src/components/ChatBubble/ChatBubble.test.tsx +55 -0
  42. package/src/components/ChatBubble/ChatBubble.tsx +66 -17
  43. package/src/components/ChatBubble/__snapshots__/ChatBubble.test.tsx.snap +73 -0
  44. package/src/components/MemoriWidget/MemoriWidget.stories.tsx +14 -0
  45. package/src/components/MemoriWidget/MemoriWidget.tsx +55 -42
  46. package/src/index.stories.tsx +59 -39
  47. package/src/index.tsx +4 -0
@@ -120,3 +120,60 @@ WithAllAddonsContents.args = {
120
120
  showFeedback: true,
121
121
  simulateUserPrompt: () => {},
122
122
  };
123
+
124
+ export const FromUserWithAvatar = Template.bind({});
125
+ FromUserWithAvatar.args = {
126
+ memori,
127
+ tenant,
128
+ user: { avatarURL: 'https://picsum.photos/200' },
129
+ message: {
130
+ fromUser: true,
131
+ text: 'Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.',
132
+ initial: false,
133
+ translatedText:
134
+ 'Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.',
135
+ },
136
+ };
137
+
138
+ export const FromUserWithCustomAvatar = Template.bind({});
139
+ FromUserWithCustomAvatar.args = {
140
+ memori,
141
+ tenant,
142
+ userAvatar: 'https://picsum.photos/200',
143
+ message: {
144
+ fromUser: true,
145
+ text: 'Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.',
146
+ initial: false,
147
+ translatedText:
148
+ 'Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.',
149
+ },
150
+ };
151
+
152
+ export const FromUserWithCustomAvatarElement = Template.bind({});
153
+ FromUserWithCustomAvatarElement.args = {
154
+ memori,
155
+ tenant,
156
+ userAvatar: <span>USER</span>,
157
+ message: {
158
+ fromUser: true,
159
+ text: 'Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.',
160
+ initial: false,
161
+ translatedText:
162
+ 'Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.',
163
+ },
164
+ };
165
+
166
+ export const FromUserWithAvatarAndCustomAvatar = Template.bind({});
167
+ FromUserWithAvatarAndCustomAvatar.args = {
168
+ memori,
169
+ tenant,
170
+ userAvatar: () => <span>USER</span>,
171
+ user: { avatarURL: 'https://picsum.photos/200' },
172
+ message: {
173
+ fromUser: true,
174
+ text: 'Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.',
175
+ initial: false,
176
+ translatedText:
177
+ 'Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.',
178
+ },
179
+ };
@@ -71,3 +71,58 @@ it('renders ChatBubble with msg generated by AI unchanged', () => {
71
71
  );
72
72
  expect(container).toMatchSnapshot();
73
73
  });
74
+
75
+ it('renders ChatBubble from user with avatar unchanged', () => {
76
+ const { container } = render(
77
+ <ChatBubble
78
+ memori={memori}
79
+ tenant={tenant}
80
+ user={{ avatarURL: 'https://picsum.photos/200' }}
81
+ message={{
82
+ fromUser: true,
83
+ text: 'Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.',
84
+ initial: false,
85
+ translatedText:
86
+ 'Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.',
87
+ }}
88
+ />
89
+ );
90
+ expect(container).toMatchSnapshot();
91
+ });
92
+
93
+ it('renders ChatBubble from user with custom avatar unchanged', () => {
94
+ const { container } = render(
95
+ <ChatBubble
96
+ memori={memori}
97
+ tenant={tenant}
98
+ userAvatar="https://picsum.photos/200"
99
+ message={{
100
+ fromUser: true,
101
+ text: 'Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.',
102
+ initial: false,
103
+ translatedText:
104
+ 'Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.',
105
+ }}
106
+ />
107
+ );
108
+ expect(container).toMatchSnapshot();
109
+ });
110
+
111
+ it('renders ChatBubble from user with avatar as react element unchanged', () => {
112
+ const { container } = render(
113
+ <ChatBubble
114
+ memori={memori}
115
+ tenant={tenant}
116
+ user={{ avatarURL: 'https://picsum.photos/200' }}
117
+ userAvatar={<span>USER</span>}
118
+ message={{
119
+ fromUser: true,
120
+ text: 'Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.',
121
+ initial: false,
122
+ translatedText:
123
+ 'Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.',
124
+ }}
125
+ />
126
+ );
127
+ expect(container).toMatchSnapshot();
128
+ });
@@ -4,10 +4,12 @@ import {
4
4
  Memori,
5
5
  Message,
6
6
  Tenant,
7
+ User,
7
8
  } from '@memori.ai/memori-api-client/dist/types';
9
+ import { Props as MemoriProps } from '../MemoriWidget/MemoriWidget';
8
10
  import { Transition } from '@headlessui/react';
9
11
  import { getResourceUrl } from '../../helpers/media';
10
- import User from '../icons/User';
12
+ import UserIcon from '../icons/User';
11
13
  import AI from '../icons/AI';
12
14
  import Tooltip from '../ui/Tooltip';
13
15
  import FeedbackButtons from '../FeedbackButtons/FeedbackButtons';
@@ -23,6 +25,8 @@ export interface Props {
23
25
  simulateUserPrompt?: (msg: string) => void;
24
26
  showAIicon?: boolean;
25
27
  isFirst?: boolean;
28
+ userAvatar?: MemoriProps['userAvatar'];
29
+ user?: User;
26
30
  }
27
31
 
28
32
  const ChatBubble: React.FC<Props> = ({
@@ -35,6 +39,8 @@ const ChatBubble: React.FC<Props> = ({
35
39
  simulateUserPrompt,
36
40
  showAIicon = true,
37
41
  isFirst = false,
42
+ user,
43
+ userAvatar,
38
44
  }) => {
39
45
  const { t } = useTranslation();
40
46
 
@@ -156,22 +162,65 @@ const ChatBubble: React.FC<Props> = ({
156
162
  </Transition.Child>
157
163
 
158
164
  {message.fromUser && (
159
- <Transition.Child
160
- as="div"
161
- className="memori-chat--bubble-avatar"
162
- enter="transition ease-in-out duration-300"
163
- enterFrom={`opacity-0 scale-075 ${
164
- message.fromUser ? 'translate-x-15' : 'translate-x--15'
165
- }`}
166
- enterTo="opacity-1 scale-1 translate-x-0"
167
- leave="transition ease-in-out duration-300"
168
- leaveFrom="opacity-1 scale-1 translate-x-0"
169
- leaveTo={`opacity-0 scale-075 ${
170
- message.fromUser ? 'translate-x-15' : 'translate-x--15'
171
- }`}
172
- >
173
- <User />
174
- </Transition.Child>
165
+ <>
166
+ {(!!userAvatar && typeof userAvatar === 'string') ||
167
+ (!userAvatar && !!user?.avatarURL?.length) ? (
168
+ <Transition.Child
169
+ as="picture"
170
+ className="memori-chat--bubble-avatar"
171
+ enter="transition ease-in-out duration-300"
172
+ enterFrom={`opacity-0 scale-075 ${
173
+ message.fromUser ? 'translate-x-15' : 'translate-x--15'
174
+ }`}
175
+ enterTo="opacity-1 scale-1 translate-x-0"
176
+ leave="transition ease-in-out duration-300"
177
+ leaveFrom="opacity-1 scale-1 translate-x-0"
178
+ leaveTo={`opacity-0 scale-075 ${
179
+ message.fromUser ? 'translate-x-15' : 'translate-x--15'
180
+ }`}
181
+ >
182
+ <img
183
+ className="memori-chat--bubble-avatar-img"
184
+ alt={user?.userName ?? 'User'}
185
+ src={userAvatar ?? user?.avatarURL}
186
+ />
187
+ </Transition.Child>
188
+ ) : !!userAvatar ? (
189
+ <Transition.Child
190
+ as="div"
191
+ className="memori-chat--bubble-avatar"
192
+ enter="transition ease-in-out duration-300"
193
+ enterFrom={`opacity-0 scale-075 ${
194
+ message.fromUser ? 'translate-x-15' : 'translate-x--15'
195
+ }`}
196
+ enterTo="opacity-1 scale-1 translate-x-0"
197
+ leave="transition ease-in-out duration-300"
198
+ leaveFrom="opacity-1 scale-1 translate-x-0"
199
+ leaveTo={`opacity-0 scale-075 ${
200
+ message.fromUser ? 'translate-x-15' : 'translate-x--15'
201
+ }`}
202
+ >
203
+ {userAvatar}
204
+ </Transition.Child>
205
+ ) : (
206
+ <Transition.Child
207
+ as="div"
208
+ className="memori-chat--bubble-avatar"
209
+ enter="transition ease-in-out duration-300"
210
+ enterFrom={`opacity-0 scale-075 ${
211
+ message.fromUser ? 'translate-x-15' : 'translate-x--15'
212
+ }`}
213
+ enterTo="opacity-1 scale-1 translate-x-0"
214
+ leave="transition ease-in-out duration-300"
215
+ leaveFrom="opacity-1 scale-1 translate-x-0"
216
+ leaveTo={`opacity-0 scale-075 ${
217
+ message.fromUser ? 'translate-x-15' : 'translate-x--15'
218
+ }`}
219
+ >
220
+ <UserIcon />
221
+ </Transition.Child>
222
+ )}
223
+ </>
175
224
  )}
176
225
  </Transition>
177
226
  </>
@@ -1,5 +1,78 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
+ exports[`renders ChatBubble from user with avatar as react element unchanged 1`] = `
4
+ <div>
5
+ <div
6
+ class="memori-chat--bubble-container memori-chat--bubble-from-user"
7
+ >
8
+ <div
9
+ class="memori-chat--bubble memori-chat--user-bubble transition ease-in-out duration-300 opacity-0 scale-09 translate-x-30"
10
+ >
11
+ <p>
12
+ Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.
13
+ </p>
14
+ </div>
15
+ <div
16
+ class="memori-chat--bubble-avatar transition ease-in-out duration-300 opacity-0 scale-075 translate-x-15"
17
+ >
18
+ <span>
19
+ USER
20
+ </span>
21
+ </div>
22
+ </div>
23
+ </div>
24
+ `;
25
+
26
+ exports[`renders ChatBubble from user with avatar unchanged 1`] = `
27
+ <div>
28
+ <div
29
+ class="memori-chat--bubble-container memori-chat--bubble-from-user"
30
+ >
31
+ <div
32
+ class="memori-chat--bubble memori-chat--user-bubble transition ease-in-out duration-300 opacity-0 scale-09 translate-x-30"
33
+ >
34
+ <p>
35
+ Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.
36
+ </p>
37
+ </div>
38
+ <picture
39
+ class="memori-chat--bubble-avatar transition ease-in-out duration-300 opacity-0 scale-075 translate-x-15"
40
+ >
41
+ <img
42
+ alt="User"
43
+ class="memori-chat--bubble-avatar-img"
44
+ src="https://picsum.photos/200"
45
+ />
46
+ </picture>
47
+ </div>
48
+ </div>
49
+ `;
50
+
51
+ exports[`renders ChatBubble from user with custom avatar unchanged 1`] = `
52
+ <div>
53
+ <div
54
+ class="memori-chat--bubble-container memori-chat--bubble-from-user"
55
+ >
56
+ <div
57
+ class="memori-chat--bubble memori-chat--user-bubble transition ease-in-out duration-300 opacity-0 scale-09 translate-x-30"
58
+ >
59
+ <p>
60
+ Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.
61
+ </p>
62
+ </div>
63
+ <picture
64
+ class="memori-chat--bubble-avatar transition ease-in-out duration-300 opacity-0 scale-075 translate-x-15"
65
+ >
66
+ <img
67
+ alt="User"
68
+ class="memori-chat--bubble-avatar-img"
69
+ src="https://picsum.photos/200"
70
+ />
71
+ </picture>
72
+ </div>
73
+ </div>
74
+ `;
75
+
3
76
  exports[`renders ChatBubble unchanged 1`] = `
4
77
  <div>
5
78
  <div
@@ -170,3 +170,17 @@ WithCustomMediaRenderer.args = {
170
170
  </div>
171
171
  ),
172
172
  };
173
+
174
+ export const WithUserAvatar = Template.bind({});
175
+ WithUserAvatar.args = {
176
+ memori,
177
+ tenant,
178
+ userAvatar: 'https://picsum.photos/200',
179
+ };
180
+
181
+ export const WithUserAvatarAsElement = Template.bind({});
182
+ WithUserAvatarAsElement.args = {
183
+ memori,
184
+ tenant,
185
+ userAvatar: <span>USER</span>,
186
+ };
@@ -14,6 +14,7 @@ import {
14
14
  Tenant,
15
15
  Asset,
16
16
  MemoriSession,
17
+ User,
17
18
  } from '@memori.ai/memori-api-client/src/types';
18
19
  import {
19
20
  SpeakerAudioDestination,
@@ -122,8 +123,18 @@ const typeMessage = (
122
123
  hasBatchQueued,
123
124
  },
124
125
  });
125
-
126
126
  document.dispatchEvent(e);
127
+
128
+ const isSafariIOS =
129
+ window.navigator.userAgent.includes('Safari') &&
130
+ !window.navigator.userAgent.includes('Chrome') &&
131
+ /iPad|iPhone|iPod/.test(navigator.userAgent);
132
+
133
+ if (isSafariIOS) {
134
+ setTimeout(() => {
135
+ document.dispatchEvent(new CustomEvent('MemoriEndSpeak'));
136
+ }, 300);
137
+ }
127
138
  };
128
139
  const typeMessageHidden = (
129
140
  message: string,
@@ -189,6 +200,11 @@ const typeBatchMessages = (
189
200
  ?.hasAttribute('disabled');
190
201
  }
191
202
 
203
+ const isSafariIOS =
204
+ window.navigator.userAgent.includes('Safari') &&
205
+ !window.navigator.userAgent.includes('Chrome') &&
206
+ /iPad|iPhone|iPod/.test(navigator.userAgent);
207
+
192
208
  const stepsGenerator = (function* () {
193
209
  yield* messages;
194
210
  })();
@@ -200,20 +216,35 @@ const typeBatchMessages = (
200
216
  const step = next.value;
201
217
 
202
218
  if (step) {
219
+ if (!areInputsDisabled()) {
220
+ disableInputs();
221
+ }
222
+
223
+ let waitForPrevious = step.waitForPrevious;
224
+ if (isSafariIOS) waitForPrevious = false;
225
+
203
226
  typeMessage(
204
227
  step.message,
205
- step.waitForPrevious,
228
+ waitForPrevious,
206
229
  step.hidden,
207
230
  step.typingText,
208
231
  step.useLoaderTextAsMsg,
209
232
  !next.done
210
233
  );
234
+
235
+ if (isSafariIOS) {
236
+ setTimeout(() => {
237
+ document.dispatchEvent(new CustomEvent('MemoriEndSpeak'));
238
+ reEnableInputs();
239
+ }, 3000);
240
+ }
211
241
  } else if (areInputsDisabled()) {
212
242
  reEnableInputs();
213
243
  }
214
244
 
215
245
  if (next.done) {
216
246
  document.removeEventListener('MemoriEndSpeak', submitNewMessage);
247
+ if (areInputsDisabled()) reEnableInputs();
217
248
  return;
218
249
  }
219
250
  };
@@ -323,6 +354,7 @@ export interface Props {
323
354
  additionalInfo?: OpenSession['additionalInfo'] & { [key: string]: string };
324
355
  customMediaRenderer?: ChatProps['customMediaRenderer'];
325
356
  additionalSettings?: JSX.Element | null;
357
+ userAvatar?: string | JSX.Element;
326
358
  }
327
359
 
328
360
  const MemoriWidget = ({
@@ -360,6 +392,7 @@ const MemoriWidget = ({
360
392
  additionalInfo,
361
393
  additionalSettings,
362
394
  customMediaRenderer,
395
+ userAvatar,
363
396
  }: Props) => {
364
397
  const { t, i18n } = useTranslation();
365
398
 
@@ -382,6 +415,10 @@ const MemoriWidget = ({
382
415
 
383
416
  const [instruct, setInstruct] = useState(false);
384
417
 
418
+ const [user, setUser] = useState<User>({
419
+ avatarURL: typeof userAvatar === 'string' ? userAvatar : undefined,
420
+ } as User);
421
+
385
422
  const [clickedStart, setClickedStart] = useState(false);
386
423
  const [gotErrorInOpening, setGotErrorInOpening] = useState(false);
387
424
 
@@ -776,13 +813,14 @@ const MemoriWidget = ({
776
813
  /**
777
814
  * Age verification
778
815
  */
779
- const minAge = memori.ageRestriction
780
- ? memori.ageRestriction
781
- : memori.nsfw
782
- ? 18
783
- : memori.enableCompletions
784
- ? 14
785
- : 0;
816
+ const minAge =
817
+ memori.ageRestriction !== undefined
818
+ ? memori.ageRestriction
819
+ : memori.nsfw
820
+ ? 18
821
+ : memori.enableCompletions
822
+ ? 14
823
+ : 0;
786
824
  const [birthDate, setBirthDate] = useState<string | undefined>();
787
825
  const [showAgeVerification, setShowAgeVerification] = useState(false);
788
826
 
@@ -1544,35 +1582,6 @@ const MemoriWidget = ({
1544
1582
  audioContext.resume().then(() => speak(text));
1545
1583
  return;
1546
1584
  }
1547
- if (isIOS && isSafari) {
1548
- audioContext.suspend();
1549
-
1550
- if (isPlayingAudio) {
1551
- try {
1552
- memoriSpeaking = false;
1553
- if (speechSynthesizer) {
1554
- speechSynthesizer.close();
1555
- speechSynthesizer = null;
1556
- }
1557
- if (audioDestination) {
1558
- audioDestination.pause();
1559
- audioDestination.close();
1560
- }
1561
- if (audioContext) {
1562
- // audioContext.close().then(() => {
1563
- // audioContext = new AudioContext();
1564
- // let buffer = audioContext.createBuffer(1, 10000, 22050);
1565
- // let source = audioContext.createBufferSource();
1566
- // source.buffer = buffer;
1567
- // source.connect(audioContext.destination);
1568
- // });
1569
- audioContext.destination.disconnect();
1570
- }
1571
- } catch (e) {
1572
- console.error('stopAudio error: ', e);
1573
- }
1574
- }
1575
- }
1576
1585
  if (audioContext.state === 'closed') {
1577
1586
  audioContext = new AudioContext();
1578
1587
  let buffer = audioContext.createBuffer(1, 10000, 22050);
@@ -1590,7 +1599,9 @@ const MemoriWidget = ({
1590
1599
  }
1591
1600
 
1592
1601
  if (!speechSynthesizer) {
1593
- audioDestination = new speechSdk.SpeakerAudioDestination();
1602
+ if (!isIOS) {
1603
+ audioDestination = new speechSdk.SpeakerAudioDestination();
1604
+ }
1594
1605
  let audioConfig =
1595
1606
  speechSdk.AudioConfig.fromSpeakerOutput(audioDestination);
1596
1607
  speechSynthesizer = new speechSdk.SpeechSynthesizer(
@@ -1628,9 +1639,6 @@ const MemoriWidget = ({
1628
1639
  memoriSpeaking = true;
1629
1640
 
1630
1641
  try {
1631
- // if (audioContext.destination.context.state === 'running') {
1632
- // audioContext.destination.disconnect();
1633
- // }
1634
1642
  audioContext.decodeAudioData(result.audioData, function (buffer) {
1635
1643
  source.buffer = buffer;
1636
1644
  source.connect(audioContext.destination);
@@ -1669,11 +1677,13 @@ const MemoriWidget = ({
1669
1677
  speechSynthesizer.close();
1670
1678
  speechSynthesizer = null;
1671
1679
  }
1680
+ emitEndSpeakEvent();
1672
1681
  }
1673
1682
  } else {
1674
1683
  audioContext.resume();
1675
1684
  setIsPlayingAudio(false);
1676
1685
  memoriSpeaking = false;
1686
+ emitEndSpeakEvent();
1677
1687
  }
1678
1688
  },
1679
1689
  error => {
@@ -1681,6 +1691,7 @@ const MemoriWidget = ({
1681
1691
  window.speechSynthesis.speak(new SpeechSynthesisUtterance(text));
1682
1692
  setIsPlayingAudio(false);
1683
1693
  memoriSpeaking = false;
1694
+ emitEndSpeakEvent();
1684
1695
  }
1685
1696
  );
1686
1697
 
@@ -2658,6 +2669,8 @@ const MemoriWidget = ({
2658
2669
  listening,
2659
2670
  isPlayingAudio,
2660
2671
  customMediaRenderer,
2672
+ user,
2673
+ userAvatar,
2661
2674
  };
2662
2675
 
2663
2676
  const integrationBackground =
@@ -52,6 +52,65 @@ Localhost.args = {
52
52
  integrationID: '82f017cc-450b-4c47-acf5-47910d336ce9',
53
53
  };
54
54
 
55
+ const TemplateWithBatchButton: Story<Props> = args => (
56
+ <div>
57
+ <button
58
+ style={{
59
+ position: 'fixed',
60
+ top: '0.5rem',
61
+ left: '0.5rem',
62
+ zIndex: 99999,
63
+ }}
64
+ onClick={() => {
65
+ window.typeBatchMessages([
66
+ {
67
+ message: 'uno di tre',
68
+ hidden: false,
69
+ waitForPrevious: true,
70
+ },
71
+ {
72
+ message: 'due di tre',
73
+ hidden: false,
74
+ waitForPrevious: true,
75
+ },
76
+ {
77
+ message: 'tre di tre',
78
+ hidden: false,
79
+ waitForPrevious: true,
80
+ },
81
+ ]);
82
+ }}
83
+ >
84
+ Start Batch
85
+ </button>
86
+ <Memori {...args} />
87
+ </div>
88
+ );
89
+ export const WithBatch = TemplateWithBatchButton.bind({});
90
+ WithBatch.args = {
91
+ ownerUserName: 'nzambello',
92
+ memoriName: 'Nicola',
93
+ tenantID: 'app.memorytwin.com',
94
+ apiURL: 'https://backend.memori.ai',
95
+ baseURL: 'https://app.memorytwin.com',
96
+ uiLang: 'it',
97
+ showShare: true,
98
+ showSettings: true,
99
+ };
100
+
101
+ export const WithCustomUserAvatar = Template.bind({});
102
+ WithCustomUserAvatar.args = {
103
+ ownerUserName: 'nzambello',
104
+ memoriName: 'Nicola',
105
+ tenantID: 'app.memorytwin.com',
106
+ apiURL: 'https://backend.memori.ai',
107
+ baseURL: 'https://app.memorytwin.com',
108
+ uiLang: 'it',
109
+ showShare: true,
110
+ showSettings: true,
111
+ userAvatar: 'https://picsum.photos/200',
112
+ };
113
+
55
114
  // export const Instruction = Template.bind({});
56
115
  // Instruction.args = {
57
116
  // ownerUserName: 'nzambello',
@@ -65,42 +124,3 @@ Localhost.args = {
65
124
  // pin: 'giver pin',
66
125
  // authToken: 'your login token',
67
126
  // };
68
-
69
- export const DemoSophia = Template.bind({});
70
- DemoSophia.args = {
71
- layout: 'TOTEM',
72
- memoriName: 'Sophia',
73
- ownerUserName: 'francescoimpellizzeri',
74
- memoriID: '57405959-a2c5-4499-adb8-bb8dcc848ad5',
75
- ownerUserID: '44ccefdb-d7a2-447e-9851-2a76be055a40',
76
- tenantID: 'nextpresent.aclambda.online',
77
- apiURL: 'https://backend.memori.ai',
78
- baseURL: 'https://nextpresent.aclambda.online',
79
- uiLang: 'it',
80
- lang: 'it',
81
- showShare: true,
82
- showSettings: true,
83
- integrationID: 'd10bbffd-26f3-4614-a092-15b215d04ffa',
84
- initialQuestion: 'Welcome Totem',
85
- contextVars: 'CONTEXT:TOTEM',
86
- // https://assets.memori.ai/api/v2/asset/6af08bf1-f011-40ea-92a2-699b7b53a53c.glb
87
- };
88
-
89
- export const DemoStefano = Template.bind({});
90
- DemoStefano.args = {
91
- layout: 'TOTEM',
92
- memoriName: 'Stefano Zingoni',
93
- ownerUserName: 'roberta.bianchi',
94
- memoriID: 'd6df4c75-8dfb-4e6d-b19f-193fa8a9bcce',
95
- ownerUserID: 'b242160e-c19c-468f-b7f8-b2dc1ce51045',
96
- tenantID: 'gruppoe.aclambda.online',
97
- apiURL: 'https://backend.memori.ai',
98
- baseURL: 'https://gruppoe.aclambda.online',
99
- uiLang: 'it',
100
- lang: 'it',
101
- showShare: true,
102
- showSettings: true,
103
- contextVars: 'CONTEXT:TOTEM',
104
- integrationID: '5712601d-6174-45e7-bfb1-b4ac71c4ff80',
105
- // https://assets.memori.ai/api/v2/asset/ed50c6a4-37cd-458b-9209-8cabfa256b30.glb
106
- };
package/src/index.tsx CHANGED
@@ -48,6 +48,7 @@ export interface Props {
48
48
  additionalInfo?: WidgetProps['additionalInfo'];
49
49
  customMediaRenderer?: WidgetProps['customMediaRenderer'];
50
50
  additionalSettings?: WidgetProps['additionalSettings'];
51
+ userAvatar?: WidgetProps['userAvatar'];
51
52
  }
52
53
 
53
54
  const getPreferredLanguages = () => {
@@ -103,6 +104,7 @@ const Memori: React.FC<Props> = ({
103
104
  additionalInfo,
104
105
  customMediaRenderer,
105
106
  additionalSettings,
107
+ userAvatar,
106
108
  }) => {
107
109
  const [memori, setMemori] = useState<IMemori>();
108
110
  const [speechKey, setSpeechKey] = useState<string | undefined>(
@@ -237,6 +239,7 @@ const Memori: React.FC<Props> = ({
237
239
  additionalInfo={additionalInfo}
238
240
  customMediaRenderer={customMediaRenderer}
239
241
  additionalSettings={additionalSettings}
242
+ userAvatar={userAvatar}
240
243
  {...(tag && pin ? { personification: { tag, pin } } : {})}
241
244
  />
242
245
  ) : (
@@ -296,6 +299,7 @@ Memori.propTypes = {
296
299
  additionalInfo: PropTypes.objectOf(PropTypes.any),
297
300
  customMediaRenderer: PropTypes.func,
298
301
  additionalSettings: PropTypes.any,
302
+ userAvatar: PropTypes.oneOfType([PropTypes.string, PropTypes.any]),
299
303
  };
300
304
 
301
305
  export default Memori;