Skip to content

Commit

Permalink
feat: add feedback buttons on acceptsFeedback
Browse files Browse the repository at this point in the history
  • Loading branch information
nzambello committed Jan 19, 2023
1 parent fd526eb commit 8be4ca4
Show file tree
Hide file tree
Showing 11 changed files with 299 additions and 5 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@
"dependencies": {
"@fontsource/exo-2": "^4.5.10",
"@headlessui/react": "1.7.4",
"@memori.ai/memori-api-client": "^0.8.3",
"@memori.ai/memori-api-client": "^0.9.0",
"@react-three/drei": "8.20.2",
"@react-three/fiber": "7.0.25",
"antd": "5.1.4",
Expand Down
18 changes: 18 additions & 0 deletions src/components/Chat/Chat.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,21 @@ OnX2aState.args = {
setAttachmentsMenuOpen: () => {},
setSendOnEnter: () => {},
};

export const AcceptsFeedback = Template.bind({});
AcceptsFeedback.args = {
memori,
tenant,
sessionID,
history,
dialogState: {
...dialogState,
acceptsFeedback: true,
},
simulateUserPrompt: () => {},
sendMessage: (msg: string) => console.log(msg),
stopListening: () => {},
resetTranscript: () => {},
setAttachmentsMenuOpen: () => {},
setSendOnEnter: () => {},
};
11 changes: 11 additions & 0 deletions src/components/Chat/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import memoriApiClient from '@memori.ai/memori-api-client';
import ChatInputs from '../ChatInputs/ChatInputs';

import './Chat.css';
import Tooltip from '../ui/Tooltip';
import FeedbackButtons from '../FeedbackButtons/FeedbackButtons';

export interface Props {
memori: Memori;
Expand Down Expand Up @@ -225,6 +227,15 @@ const Chat: React.FC<Props> = ({
</div>
)}

{index === history.length - 1 &&
!message.fromUser &&
dialogState?.acceptsFeedback && (
<FeedbackButtons
memori={memori}
simulateUserPrompt={simulateUserPrompt}
/>
)}

<MediaWidget
simulateUserPrompt={simulateUserPrompt}
media={message?.media?.filter(
Expand Down
23 changes: 23 additions & 0 deletions src/components/FeedbackButtons/FeedbackButtons.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.memori-chat--feedback {
padding: 0 3.5rem;
margin-top: -0.5em;
margin-bottom: 1.5em;
}

.memori-chat--feedback button {
padding: 0.5em;
opacity: 0.4;
transition: all 0.3s ease-in-out;
}

.memori-chat--feedback button:hover,
.memori-chat--feedback button:focus {
opacity: 1;
}

.memori-chat--feedback button .memori-button--icon svg {
fill: none;
}
.memori-chat--feedback button .memori-button--icon svg.memori-chat--feedback-clicked {
fill: var(--memori-primary);
}
25 changes: 25 additions & 0 deletions src/components/FeedbackButtons/FeedbackButtons.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';
import { Meta, Story } from '@storybook/react';
import FeedbackButtons, { Props } from './FeedbackButtons';
import { memori } from '../../mocks/data';

const meta: Meta = {
title: 'Feedback Buttons',
component: FeedbackButtons,
argTypes: {},
parameters: {
controls: { expanded: true },
},
};

export default meta;

const Template: Story<Props> = args => <FeedbackButtons {...args} />;

// By passing using the Args format for exported stories, you can control the props for a component for reuse in a test
// https://storybook.js.org/docs/react/workflows/unit-testing
export const Default = Template.bind({});
Default.args = {
memori,
simulateUserPrompt: () => {},
};
11 changes: 11 additions & 0 deletions src/components/FeedbackButtons/FeedbackButtons.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';
import { render } from '@testing-library/react';
import { memori } from '../../mocks/data';
import FeedbackButtons from './FeedbackButtons';

it('renders FeedbackButtons unchanged', () => {
const { container } = render(
<FeedbackButtons memori={memori} simulateUserPrompt={jest.fn()} />
);
expect(container).toMatchSnapshot();
});
75 changes: 75 additions & 0 deletions src/components/FeedbackButtons/FeedbackButtons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { Memori } from '@memori.ai/memori-api-client/dist/types';
import React, { useState } from 'react';
import Tooltip from '../ui/Tooltip';
import Button from '../ui/Button';
import ThumbUp from '../icons/ThumbUp';
import ThumbDown from '../icons/ThumbDown';

import './FeedbackButtons.css';

const feedbackMsgs = {
'it-IT': 'Non è quello che ti ho chiesto',
'fr-FR': "Ce n'est pas ce que je t'ai demandé",
'en-GB': "It's not what I asked",
};

export interface Props {
memori: Memori;
simulateUserPrompt: (msg: string) => void;
}

const FeedbackButtons = ({ memori, simulateUserPrompt }: Props) => {
const [clicked, setClicked] = useState<'up' | 'down'>();
const feedbackMsg =
memori.culture === 'it-IT'
? feedbackMsgs['it-IT']
: memori.culture === 'fr-FR'
? feedbackMsgs['fr-FR']
: feedbackMsgs['en-GB'];

return (
<div className="memori-chat--feedback">
<Button
ghost
shape="circle"
onClick={() => {
if (clicked === 'up') {
setClicked(undefined);
} else {
setClicked('up');
}
}}
icon={
<ThumbUp
className={
clicked === 'up' ? 'memori-chat--feedback-clicked' : undefined
}
/>
}
/>
<Tooltip content={feedbackMsg}>
<Button
ghost
shape="circle"
onClick={() => {
if (clicked === 'down') {
setClicked(undefined);
} else {
setClicked('down');
}
simulateUserPrompt(feedbackMsg);
}}
icon={
<ThumbDown
className={
clicked === 'down' ? 'memori-chat--feedback-clicked' : undefined
}
/>
}
/>
</Tooltip>
</div>
);
};

export default FeedbackButtons;
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`renders FeedbackButtons unchanged 1`] = `
<div>
<div
class="memori-chat--feedback"
>
<button
class="memori-button memori-button--ghost memori-button--circle memori-button--padded memori-button--icon-only"
>
<span
class="memori-button--icon"
>
<svg
aria-hidden="true"
fill="none"
focusable="false"
role="img"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
tabindex="-1"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M14 9V5a3 3 0 00-3-3l-4 9v11h11.28a2 2 0 002-1.7l1.38-9a2 2 0 00-2-2.3zM7 22H4a2 2 0 01-2-2v-7a2 2 0 012-2h3"
/>
</svg>
</span>
</button>
<div
class="memori-tooltip"
>
<div
class="memori-tooltip--content"
>
Non è quello che ti ho chiesto
</div>
<div
class="memori-tooltip--trigger"
>
<button
class="memori-button memori-button--ghost memori-button--circle memori-button--padded memori-button--icon-only"
>
<span
class="memori-button--icon"
>
<svg
aria-hidden="true"
fill="none"
focusable="false"
role="img"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
tabindex="-1"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M10 15v4a3 3 0 003 3l4-9V2H5.72a2 2 0 00-2 1.7l-1.38 9a2 2 0 002 2.3zm7-13h2.67A2.31 2.31 0 0122 4v7a2.31 2.31 0 01-2.33 2H17"
/>
</svg>
</span>
</button>
</div>
</div>
</div>
</div>
`;
29 changes: 29 additions & 0 deletions src/components/icons/ThumbDown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';

const ThumbDown = ({
className,
title,
}: {
className?: string;
title?: string;
}) => (
<svg
{...(!title ? { 'aria-hidden': 'true' } : {})}
focusable="false"
role="img"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
tabIndex={-1}
className={className}
aria-label={title}
>
<path d="M10 15v4a3 3 0 003 3l4-9V2H5.72a2 2 0 00-2 1.7l-1.38 9a2 2 0 002 2.3zm7-13h2.67A2.31 2.31 0 0122 4v7a2.31 2.31 0 01-2.33 2H17"></path>
</svg>
);

export default ThumbDown;
29 changes: 29 additions & 0 deletions src/components/icons/ThumbUp.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';

const ThumbUp = ({
className,
title,
}: {
className?: string;
title?: string;
}) => (
<svg
{...(!title ? { 'aria-hidden': 'true' } : {})}
focusable="false"
role="img"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
tabIndex={-1}
className={className}
aria-label={title}
>
<path d="M14 9V5a3 3 0 00-3-3l-4 9v11h11.28a2 2 0 002-1.7l1.38-9a2 2 0 00-2-2.3zM7 22H4a2 2 0 01-2-2v-7a2 2 0 012-2h3"></path>
</svg>
);

export default ThumbUp;
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1954,10 +1954,10 @@
resolved "https://registry.yarnpkg.com/@mdx-js/util/-/util-1.6.22.tgz#219dfd89ae5b97a8801f015323ffa4b62f45718b"
integrity sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA==

"@memori.ai/memori-api-client@^0.8.3":
version "0.8.3"
resolved "https://registry.yarnpkg.com/@memori.ai/memori-api-client/-/memori-api-client-0.8.3.tgz#862e8096542a9f08f689126638de84d219ec3252"
integrity sha512-iwr7uYJVMBkjkv501gnx4PlOfrbEsBdbiFO8XPJHU8qGngq5158hUvxt8kEwOvjUpM4JaXgC7saT0Q4F86jcoQ==
"@memori.ai/memori-api-client@^0.9.0":
version "0.9.0"
resolved "https://registry.yarnpkg.com/@memori.ai/memori-api-client/-/memori-api-client-0.9.0.tgz#d549c7846ee37338a83e8e686c7e97d2fd4fcd1b"
integrity sha512-5bZXFKrMPJ+JxHfTfaHabMykUcyFXpE3Vl0FSCQ/m/ueCwl9DN8f5XdcPEKBw3GmKHhz/0KSR06eFn6bq1hukw==
dependencies:
cross-fetch "^3.1.5"
microsoft-cognitiveservices-speech-sdk "1.20.0"
Expand Down

0 comments on commit 8be4ca4

Please sign in to comment.