From 31921152d8c19dd96d22c4000228d7a31ee12df3 Mon Sep 17 00:00:00 2001 From: relja-rasa Date: Wed, 5 Feb 2025 15:26:15 +0100 Subject: [PATCH] Apply new interface format for Rating --- e2e/cypress/fixtures/chatbotWidgetData.ts | 7 +- .../types/parsed-message.types.ts | 4 +- .../utils/message-parsers.test.ts | 18 +++-- .../message-parser/utils/message-parsers.ts | 7 +- .../sdk/src/types/server-response.types.ts | 3 +- packages/ui/src/components.d.ts | 28 +++---- .../ui/src/components/rating/rating.test.tsx | 73 ++++++++++++------- packages/ui/src/components/rating/rating.tsx | 29 +++++--- packages/ui/src/components/rating/readme.md | 15 ++-- .../rasa-chatbot-widget.tsx | 26 ++++--- 10 files changed, 126 insertions(+), 84 deletions(-) diff --git a/e2e/cypress/fixtures/chatbotWidgetData.ts b/e2e/cypress/fixtures/chatbotWidgetData.ts index cd58be2..863aeae 100644 --- a/e2e/cypress/fixtures/chatbotWidgetData.ts +++ b/e2e/cypress/fixtures/chatbotWidgetData.ts @@ -144,10 +144,11 @@ const botResponses = { type: 'rating', text: 'How would you rate this answer?', options: [ - { value: 'positive', icon: '😊', label: 'Positive' }, - { value: 'neutral', icon: '😐', label: 'Neutral' }, - { value: 'negative', icon: '☚ī¸', label: 'Negative' }, + { value: 'positive', payload: '/give_positive_feedback' }, + { value: 'neutral', payload: '/give_neutral_feedback' }, + { value: 'negative', payload: '/give_negative_feedback' }, ], + message: 'We appreciate your feedback!', // ✅ Added thank-you message }, }; diff --git a/packages/sdk/src/message-parser/types/parsed-message.types.ts b/packages/sdk/src/message-parser/types/parsed-message.types.ts index 330781b..5fa9cf9 100644 --- a/packages/sdk/src/message-parser/types/parsed-message.types.ts +++ b/packages/sdk/src/message-parser/types/parsed-message.types.ts @@ -66,10 +66,12 @@ export interface AccordionMessage extends BaseMessage { export interface RatingMessage extends BaseMessage { type: typeof MESSAGE_TYPES.RATING; text: string; - options: { value: string; icon: string; label: string }[]; + options: { value: string; payload: string }[]; // ✅ Updated: Removed icon/label, added payload + message: string; // ✅ Added: To store the thank-you message from Rasa } + export type Message = | AccordionMessage | CarouselMessage diff --git a/packages/sdk/src/message-parser/utils/message-parsers.test.ts b/packages/sdk/src/message-parser/utils/message-parsers.test.ts index 1f62059..c5917a5 100644 --- a/packages/sdk/src/message-parser/utils/message-parsers.test.ts +++ b/packages/sdk/src/message-parser/utils/message-parsers.test.ts @@ -185,22 +185,26 @@ describe('MessageParsers', () => { type: RESPONSE_MESSAGE_TYPES.RATING, text: 'How would you rate this?', options: [ - { value: 'positive', icon: '😊', label: 'Positive' }, - { value: 'neutral', icon: '😐', label: 'Neutral' }, - { value: 'negative', icon: '☚ī¸', label: 'Negative' }, + { value: 'positive', payload: '/give_positive_feedback' }, + { value: 'neutral', payload: '/give_neutral_feedback' }, + { value: 'negative', payload: '/give_negative_feedback' }, ], + message: 'We appreciate your feedback!', // ✅ Added the message field }; + const expected: RatingMessage = { sender, type: MESSAGE_TYPES.RATING, text: 'How would you rate this?', options: [ - { value: 'positive', icon: '😊', label: 'Positive' }, - { value: 'neutral', icon: '😐', label: 'Neutral' }, - { value: 'negative', icon: '☚ī¸', label: 'Negative' }, + { value: 'positive', payload: '/give_positive_feedback' }, + { value: 'neutral', payload: '/give_neutral_feedback' }, + { value: 'negative', payload: '/give_negative_feedback' }, ], + message: 'We appreciate your feedback!', // ✅ Ensure message is tested }; - + expect(MessageParsers.rating(ratingResponse, sender)).toEqual(expected); }); + }); diff --git a/packages/sdk/src/message-parser/utils/message-parsers.ts b/packages/sdk/src/message-parser/utils/message-parsers.ts index a2960cf..f0d535b 100644 --- a/packages/sdk/src/message-parser/utils/message-parsers.ts +++ b/packages/sdk/src/message-parser/utils/message-parsers.ts @@ -88,9 +88,14 @@ export const MessageParsers = { sender, type: MESSAGE_TYPES.RATING, text: message.text, - options: message.options, + options: message.options.map(option => ({ + value: option.value, + payload: option.payload // ✅ Ensure payload is included + })), + message: message.message, // ✅ Ensure the thank-you message is passed timestamp: message.timestamp, }), + }; export type MessageParsersType = typeof MessageParsers; diff --git a/packages/sdk/src/types/server-response.types.ts b/packages/sdk/src/types/server-response.types.ts index 5ca7f45..3858b37 100644 --- a/packages/sdk/src/types/server-response.types.ts +++ b/packages/sdk/src/types/server-response.types.ts @@ -31,7 +31,8 @@ export interface CarouselResponse extends BaseMessageResponse { export interface RatingResponse extends BaseMessageResponse { type: typeof RESPONSE_MESSAGE_TYPES.RATING; text: string; - options: { value: string; icon: string; label: string }[]; + options: { value: string; payload: string }[]; // ✅ Updated: Removed icon/label, added payload + message: string; // ✅ Added: To store the thank-you message from Rasa } export interface QuickReplyResponse extends BaseMessageResponse { diff --git a/packages/ui/src/components.d.ts b/packages/ui/src/components.d.ts index 20086fe..edff22e 100644 --- a/packages/ui/src/components.d.ts +++ b/packages/ui/src/components.d.ts @@ -424,17 +424,17 @@ export namespace Components { } interface RasaRating { /** - * List of rating options + * Customizable message from Rasa (Previously thankYouMessage) */ - "options": string | { value: string }[]; + "message": string; /** - * Instructional text for the rating component + * List of rating options from Rasa */ - "text": string; + "options": string | { value: string; payload: string }[]; /** - * Customizable thank-you message from Rasa + * Instructional text for the rating component */ - "thankYouMessage": string; + "text": string; } interface RasaSessionDivider { /** @@ -741,7 +741,7 @@ declare global { new (): HTMLRasaQuickReplyElement; }; interface HTMLRasaRatingElementEventMap { - "ratingSelected": { value: string }; + "ratingSelected": { value: string; payload: string }; } interface HTMLRasaRatingElement extends Components.RasaRating, HTMLStencilElement { addEventListener(type: K, listener: (this: HTMLRasaRatingElement, ev: RasaRatingCustomEvent) => any, options?: boolean | AddEventListenerOptions): void; @@ -1299,22 +1299,22 @@ declare namespace LocalJSX { "quickReplyId"?: string; } interface RasaRating { + /** + * Customizable message from Rasa (Previously thankYouMessage) + */ + "message"?: string; /** * Event emitted when a rating is selected */ - "onRatingSelected"?: (event: RasaRatingCustomEvent<{ value: string }>) => void; + "onRatingSelected"?: (event: RasaRatingCustomEvent<{ value: string; payload: string }>) => void; /** - * List of rating options + * List of rating options from Rasa */ - "options"?: string | { value: string }[]; + "options"?: string | { value: string; payload: string }[]; /** * Instructional text for the rating component */ "text"?: string; - /** - * Customizable thank-you message from Rasa - */ - "thankYouMessage"?: string; } interface RasaSessionDivider { /** diff --git a/packages/ui/src/components/rating/rating.test.tsx b/packages/ui/src/components/rating/rating.test.tsx index a3b57a2..0961df9 100644 --- a/packages/ui/src/components/rating/rating.test.tsx +++ b/packages/ui/src/components/rating/rating.test.tsx @@ -6,38 +6,21 @@ describe('rasa-rating', () => { const page = await newSpecPage({ components: [RasaRating], html: ``, + { "value": "positive", "payload": "/give_positive_feedback" }, + { "value": "neutral", "payload": "/give_neutral_feedback" }, + { "value": "negative", "payload": "/give_negative_feedback" } + ]' message="We appreciate your feedback!">`, }); - expect(page.root.shadowRoot).toEqualHtml(` -
-

How would you rate this answer?

-
- - - -
-
- `); + expect(page.root.shadowRoot.innerHTML).toContain('How would you rate this answer?'); + expect(page.root.shadowRoot.querySelectorAll('.rasa-rating__option').length).toBe(3); }); - it('emits ratingSelected event on option click', async () => { + it('emits ratingSelected event with payload on option click', async () => { const page = await newSpecPage({ components: [RasaRating], html: ``, }); @@ -49,7 +32,10 @@ describe('rasa-rating', () => { await page.waitForChanges(); expect(ratingSelectedSpy).toHaveBeenCalled(); - expect(ratingSelectedSpy.mock.calls[0][0].detail).toEqual({ value: 'positive' }); + expect(ratingSelectedSpy.mock.calls[0][0].detail).toEqual({ + value: 'positive', + payload: '/give_positive_feedback' + }); }); it('renders fallback when no options are provided', async () => { @@ -66,8 +52,8 @@ describe('rasa-rating', () => { const page = await newSpecPage({ components: [RasaRating], html: ``, }); @@ -82,4 +68,35 @@ describe('rasa-rating', () => { expect(positiveOption.classList.contains('rasa-rating__option--selected')).toBe(true); expect(neutralOption.classList.contains('rasa-rating__option--selected')).toBe(false); }); + + it('displays message after selection', async () => { + const page = await newSpecPage({ + components: [RasaRating], + html: ``, + }); + + const option = page.root.shadowRoot.querySelector('.rasa-rating__option'); + option.dispatchEvent(new Event('click')); + await page.waitForChanges(); + + expect(page.root.shadowRoot.querySelector('.rasa-rating__options')).toBeNull(); // Ensure options disappear + expect(page.root.shadowRoot.textContent).toContain("We appreciate your feedback!"); // Ensure message is displayed + }); + + it('displays default message if none is provided', async () => { + const page = await newSpecPage({ + components: [RasaRating], + html: ``, + }); + + const option = page.root.shadowRoot.querySelector('.rasa-rating__option'); + option.dispatchEvent(new Event('click')); + await page.waitForChanges(); + + expect(page.root.shadowRoot.textContent).toContain("Thank you for your feedback!"); // Default message should appear + }); }); diff --git a/packages/ui/src/components/rating/rating.tsx b/packages/ui/src/components/rating/rating.tsx index 728fa11..0c55f73 100644 --- a/packages/ui/src/components/rating/rating.tsx +++ b/packages/ui/src/components/rating/rating.tsx @@ -13,22 +13,22 @@ export class RasaRating { @Prop() text: string; /** - * List of rating options + * List of rating options from Rasa */ - @Prop() options: string | { value: string }[] = []; + @Prop() options: string | { value: string; payload: string }[] = []; /** - * Customizable thank-you message from Rasa + * Customizable message from Rasa (Previously thankYouMessage) */ - @Prop() thankYouMessage: string = "Thank you for your feedback!"; + @Prop() message: string = "Thank you for your feedback!"; /** * Event emitted when a rating is selected */ - @Event() ratingSelected: EventEmitter<{ value: string }>; + @Event() ratingSelected: EventEmitter<{ value: string; payload: string }>; /** - * State to track the currently selected option + * State to track the selected option */ @State() selectedOption: string | null = null; @@ -38,16 +38,21 @@ export class RasaRating { @State() hasVoted: boolean = false; componentDidLoad() { + console.log("Received Props:", { + text: this.text, + options: this.options, + message: this.message + }); messageQueueService.completeRendering(); } - private handleOptionClick(optionValue: string) { + private handleOptionClick(optionValue: string, payload: string) { this.selectedOption = optionValue; this.hasVoted = true; - this.ratingSelected.emit({ value: optionValue }); + this.ratingSelected.emit({ value: optionValue, payload }); // Send payload to Rasa } - private getParsedOptions(): { value: string }[] { + private getParsedOptions(): { value: string; payload: string }[] { if (typeof this.options === 'string') { try { return JSON.parse(this.options); @@ -93,7 +98,7 @@ export class RasaRating { return (
{this.hasVoted ? ( -

{this.thankYouMessage}

// Thank-you message from Rasa +

{this.message}

// Dynamic message from Rasa ) : (

{this.text}

@@ -105,8 +110,8 @@ export class RasaRating { 'rasa-rating__option': true, 'rasa-rating__option--selected': this.selectedOption === option.value, }} - onClick={() => this.handleOptionClick(option.value)} - innerHTML={this.getIconForValue(option.value)} // Injecting the SVG directly into the button + onClick={() => this.handleOptionClick(option.value, option.payload)} + innerHTML={this.getIconForValue(option.value)} > ))}
diff --git a/packages/ui/src/components/rating/readme.md b/packages/ui/src/components/rating/readme.md index e32fcc9..859fcec 100644 --- a/packages/ui/src/components/rating/readme.md +++ b/packages/ui/src/components/rating/readme.md @@ -7,17 +7,18 @@ ## Properties -| Property | Attribute | Description | Type | Default | -| --------- | --------- | ------------------------------------------- | ------------------------------------------------------------- | ----------- | -| `options` | `options` | List of rating options | `string \| { value: string; icon: string; label: string; }[]` | `[]` | -| `text` | `text` | Instructional text for the rating component | `string` | `undefined` | +| Property | Attribute | Description | Type | Default | +| --------- | --------- | ----------------------------------------------------------- | ------------------------------------------------- | -------------------------------- | +| `message` | `message` | Customizable message from Rasa (Previously thankYouMessage) | `string` | `"Thank you for your feedback!"` | +| `options` | `options` | List of rating options from Rasa | `string \| { value: string; payload: string; }[]` | `[]` | +| `text` | `text` | Instructional text for the rating component | `string` | `undefined` | ## Events -| Event | Description | Type | -| ---------------- | --------------------------------------- | --------------------------------- | -| `ratingSelected` | Event emitted when a rating is selected | `CustomEvent<{ value: string; }>` | +| Event | Description | Type | +| ---------------- | --------------------------------------- | -------------------------------------------------- | +| `ratingSelected` | Event emitted when a rating is selected | `CustomEvent<{ value: string; payload: string; }>` | ## Dependencies diff --git a/packages/ui/src/rasa-chatbot-widget/rasa-chatbot-widget.tsx b/packages/ui/src/rasa-chatbot-widget/rasa-chatbot-widget.tsx index f80b414..3174165 100644 --- a/packages/ui/src/rasa-chatbot-widget/rasa-chatbot-widget.tsx +++ b/packages/ui/src/rasa-chatbot-widget/rasa-chatbot-widget.tsx @@ -402,16 +402,22 @@ export class RasaChatbotWidget { ); - case MESSAGE_TYPES.RATING: - return ( - - console.log("Rating selected:", event.detail.value)} - > - - ); + case MESSAGE_TYPES.RATING: + return ( + + { + console.log("Rating selected:", event.detail.value); + console.log("Payload triggered:", event.detail.payload); // ✅ Log the payload from Rasa + // Send the payload to Rasa backend (if needed) + }} + > + + ); + } }