From 36abed9ce77badb7bda715eee973fbb1e3d4ce25 Mon Sep 17 00:00:00 2001
From: nzambello
Date: Mon, 13 Nov 2023 11:11:27 +0200
Subject: [PATCH] feat: add user avatar
---
README.md | 1 +
package.json | 2 +-
src/components/Chat/Chat.stories.tsx | 51 +
src/components/Chat/Chat.test.tsx | 96 +
src/components/Chat/Chat.tsx | 7 +
.../Chat/__snapshots__/Chat.test.tsx.snap | 1581 ++++++++++++++---
.../ChatBubble/ChatBubble.stories.tsx | 57 +
src/components/ChatBubble/ChatBubble.test.tsx | 55 +
src/components/ChatBubble/ChatBubble.tsx | 83 +-
.../__snapshots__/ChatBubble.test.tsx.snap | 73 +
.../MemoriWidget/MemoriWidget.stories.tsx | 14 +
src/components/MemoriWidget/MemoriWidget.tsx | 9 +
src/index.stories.tsx | 13 +
src/index.tsx | 4 +
yarn.lock | 10 +-
15 files changed, 1781 insertions(+), 275 deletions(-)
diff --git a/README.md b/README.md
index 2089bf19..417ecf0c 100644
--- a/README.md
+++ b/README.md
@@ -87,6 +87,7 @@ const App = () => (
| `customLayout` | | `React.FC` | | Custom layout component, see [below](#custom-layout) |
| `customMediaRenderer` | | `(mimeType: string) => JSX.Element \| null` | | Custom media renderer, see [below](#custom-media-renderer) |
| `additionalSettings` | | `JSX.Element` | | Custom JSX or component to render within the settings drawer |
+| `userAvatar` | | `string` | | Custom URL or React element to use as user avatar |
\*: one of these pairs is required: `memoriName` + `ownerUserName`, `memoriID` + `ownerUserID`
diff --git a/package.json b/package.json
index 4f4da80c..9b1cef3a 100644
--- a/package.json
+++ b/package.json
@@ -283,7 +283,7 @@
"dependencies": {
"@fontsource/exo-2": "^4.5.10",
"@headlessui/react": "1.7.4",
- "@memori.ai/memori-api-client": "^2.2.2",
+ "@memori.ai/memori-api-client": "^2.4.0",
"@react-three/drei": "8.20.2",
"@react-three/fiber": "7.0.25",
"antd": "4.18.9",
diff --git a/src/components/Chat/Chat.stories.tsx b/src/components/Chat/Chat.stories.tsx
index b85a4808..dd6b3e31 100644
--- a/src/components/Chat/Chat.stories.tsx
+++ b/src/components/Chat/Chat.stories.tsx
@@ -232,3 +232,54 @@ WithAIGeneratedMessages.args = {
setAttachmentsMenuOpen: () => {},
setSendOnEnter: () => {},
};
+
+export const WithUser = Template.bind({});
+WithUser.args = {
+ user: { avatarURL: 'https://picsum.photos/200' },
+ memori,
+ tenant,
+ sessionID,
+ history,
+ dialogState,
+ layout: 'DEFAULT',
+ simulateUserPrompt: () => {},
+ sendMessage: (msg: string) => console.log(msg),
+ stopListening: () => {},
+ resetTranscript: () => {},
+ setAttachmentsMenuOpen: () => {},
+ setSendOnEnter: () => {},
+};
+
+export const WithCustomUserAvatar = Template.bind({});
+WithCustomUserAvatar.args = {
+ userAvatar: 'https://picsum.photos/200',
+ memori,
+ tenant,
+ sessionID,
+ history,
+ dialogState,
+ layout: 'DEFAULT',
+ simulateUserPrompt: () => {},
+ sendMessage: (msg: string) => console.log(msg),
+ stopListening: () => {},
+ resetTranscript: () => {},
+ setAttachmentsMenuOpen: () => {},
+ setSendOnEnter: () => {},
+};
+
+export const WithCustomUserAvatarAsElement = Template.bind({});
+WithCustomUserAvatarAsElement.args = {
+ userAvatar: USER,
+ memori,
+ tenant,
+ sessionID,
+ history,
+ dialogState,
+ layout: 'DEFAULT',
+ simulateUserPrompt: () => {},
+ sendMessage: (msg: string) => console.log(msg),
+ stopListening: () => {},
+ resetTranscript: () => {},
+ setAttachmentsMenuOpen: () => {},
+ setSendOnEnter: () => {},
+};
diff --git a/src/components/Chat/Chat.test.tsx b/src/components/Chat/Chat.test.tsx
index e771c172..7798ebb2 100644
--- a/src/components/Chat/Chat.test.tsx
+++ b/src/components/Chat/Chat.test.tsx
@@ -287,3 +287,99 @@ it('renders Chat on X2a state unchanged', () => {
);
expect(container).toMatchSnapshot();
});
+
+it('renders Chat with user unchanged', () => {
+ const { container } = render(
+
+ );
+ expect(container).toMatchSnapshot();
+});
+
+it('renders Chat with custom user avatar unchanged', () => {
+ const { container } = render(
+
+ );
+ expect(container).toMatchSnapshot();
+});
+
+it('renders Chat with custom user avatar as react element unchanged', () => {
+ const { container } = render(
+ USER}
+ memori={memori}
+ tenant={tenant}
+ dialogState={dialogState}
+ layout="DEFAULT"
+ setDialogState={jest.fn()}
+ client={client}
+ history={history}
+ pushMessage={jest.fn()}
+ sessionID={sessionID}
+ simulateUserPrompt={jest.fn()}
+ selectReceiverTag={jest.fn()}
+ setAttachmentsMenuOpen={jest.fn()}
+ setSendOnEnter={jest.fn()}
+ userMessage=""
+ onChangeUserMessage={jest.fn()}
+ sendMessage={jest.fn()}
+ isPlayingAudio={false}
+ stopAudio={jest.fn()}
+ showMicrophone={false}
+ listening={false}
+ startListening={jest.fn()}
+ stopListening={jest.fn()}
+ resetTranscript={jest.fn()}
+ />
+ );
+ expect(container).toMatchSnapshot();
+});
diff --git a/src/components/Chat/Chat.tsx b/src/components/Chat/Chat.tsx
index 2225d2ee..de17d6ce 100644
--- a/src/components/Chat/Chat.tsx
+++ b/src/components/Chat/Chat.tsx
@@ -5,6 +5,7 @@ import {
Memori,
Message,
Tenant,
+ User,
} from '@memori.ai/memori-api-client/dist/types';
import { hasTouchscreen } from '../../helpers/utils';
import { getResourceUrl } from '../../helpers/media';
@@ -59,6 +60,8 @@ export interface Props {
resetTranscript: () => void;
customMediaRenderer?: MediaWidgetProps['customMediaRenderer'];
layout: MemoriProps['layout'];
+ userAvatar?: MemoriProps['userAvatar'];
+ user?: User;
}
const Chat: React.FC = ({
@@ -98,6 +101,8 @@ const Chat: React.FC = ({
stopListening,
resetTranscript,
customMediaRenderer,
+ user,
+ userAvatar,
}) => {
const scrollToBottom = () => {
setTimeout(() => {
@@ -194,6 +199,8 @@ const Chat: React.FC = ({
!message.fromUser &&
dialogState?.acceptsFeedback
}
+ user={user}
+ userAvatar={userAvatar}
/>
{showDates && !!message.timestamp && (
`;
-exports[`renders Chat with dates unchanged 1`] = `
+exports[`renders Chat with custom user avatar as react element unchanged 1`] = `
-
- 13:00:00
-
@@ -1704,24 +1699,11 @@ exports[`renders Chat with dates unchanged 1`] = `
-
- 13:00:00
-
@@ -1748,11 +1730,6 @@ exports[`renders Chat with dates unchanged 1`] = `
-
- 13:00:00
-
@@ -1769,24 +1746,11 @@ exports[`renders Chat with dates unchanged 1`] = `
-
- 13:00:00
-
@@ -1813,11 +1777,6 @@ exports[`renders Chat with dates unchanged 1`] = `
-
- 13:00:00
-
-
- 13:00:00
-
@@ -1954,11 +1900,6 @@ exports[`renders Chat with dates unchanged 1`] = `
-
- 13:00:00
-
@@ -1980,7 +1921,7 @@ exports[`renders Chat with dates unchanged 1`] = `
aria-haspopup="true"
class="memori-button memori-button--circle memori-button--icon-only memori-share-button--button memori--conversation-button"
data-headlessui-state=""
- id="headlessui-menu-button-:r8:"
+ id="headlessui-menu-button-:rk:"
type="button"
>
`;
-exports[`renders Chat with hints unchanged 1`] = `
+exports[`renders Chat with custom user avatar unchanged 1`] = `
-
+
+
-
+
+
-
+
+
-
@@ -2385,7 +2282,7 @@ exports[`renders Chat with hints unchanged 1`] = `
aria-haspopup="true"
class="memori-button memori-button--circle memori-button--icon-only memori-share-button--button memori--conversation-button"
data-headlessui-state=""
- id="headlessui-menu-button-:r4:"
+ id="headlessui-menu-button-:ri:"
type="button"
>
`;
-exports[`renders Chat with media unchanged 1`] = `
+exports[`renders Chat with dates unchanged 1`] = `
+
+ 13:00:00
+
@@ -2531,6 +2433,11 @@ exports[`renders Chat with media unchanged 1`] = `
+
+ 13:00:00
+
@@ -2557,6 +2464,11 @@ exports[`renders Chat with media unchanged 1`] = `
+
+ 13:00:00
+
@@ -2586,6 +2498,11 @@ exports[`renders Chat with media unchanged 1`] = `
+
+ 13:00:00
+
@@ -2608,31 +2525,35 @@ exports[`renders Chat with media unchanged 1`] = `
class="memori-chat--bubble transition ease-in-out duration-300 opacity-0 scale-09 translate-x--30"
>
- Ecco qui delle cose per te.
+ Ecco qui come.
+
+ 13:00:00
+