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`] = `
- + + USER +
- - 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`] = `
- + + USER +
- - 13:00:00 -
@@ -1813,11 +1777,6 @@ exports[`renders Chat with dates unchanged 1`] = `

- - 13:00:00 -
@@ -1910,24 +1869,11 @@ exports[`renders Chat with dates unchanged 1`] = `
- + + USER +
- - 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`] = `
-
- -
+ User +
-
- -
+ User +
-
- -
+ User +
-
-
    -
  • - -
  • -
  • - -
  • -
-
@@ -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 +
- - - Image 0 - - + + +
-
- -
-
-
- - +
+
+
+
+

+ Ah, grazie! Ciao! +

+
+
+ +
+
+ + 13:00:00 + +
+
+ + + Memori + +
+

+ Arrivederci. +

+
+
+ + 13:00:00 + +
+
+
+
+
+
+ +
+
+
+