Skip to content

Commit

Permalink
Apply new interface format for Rating
Browse files Browse the repository at this point in the history
  • Loading branch information
relja-rasa committed Feb 5, 2025
1 parent f4e8558 commit 8c1f1be
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 81 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 11 additions & 7 deletions packages/sdk/src/message-parser/utils/message-parsers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});

});
7 changes: 6 additions & 1 deletion packages/sdk/src/message-parser/utils/message-parsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 3 additions & 1 deletion packages/sdk/src/types/server-response.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ 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 {
text?: string;
quick_replies: { content_type: string; payload: string; title: string; isSelected?: boolean }[];
Expand Down
28 changes: 14 additions & 14 deletions packages/ui/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
/**
Expand Down Expand Up @@ -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<K extends keyof HTMLRasaRatingElementEventMap>(type: K, listener: (this: HTMLRasaRatingElement, ev: RasaRatingCustomEvent<HTMLRasaRatingElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
Expand Down Expand Up @@ -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 {
/**
Expand Down
73 changes: 45 additions & 28 deletions packages/ui/src/components/rating/rating.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,21 @@ describe('rasa-rating', () => {
const page = await newSpecPage({
components: [RasaRating],
html: `<rasa-rating text="How would you rate this answer?" options='[
{ "value": "positive", "icon": "😊", "label": "Positive" },
{ "value": "neutral", "icon": "😐", "label": "Neutral" },
{ "value": "negative", "icon": "☹️", "label": "Negative" }
]'></rasa-rating>`,
{ "value": "positive", "payload": "/give_positive_feedback" },
{ "value": "neutral", "payload": "/give_neutral_feedback" },
{ "value": "negative", "payload": "/give_negative_feedback" }
]' message="We appreciate your feedback!"></rasa-rating>`,
});

expect(page.root.shadowRoot).toEqualHtml(`
<div class="rasa-rating">
<p class="rasa-rating__text">How would you rate this answer?</p>
<div class="rasa-rating__options">
<button class="rasa-rating__option">
<span class="rasa-rating__icon">😊</span>
<span class="rasa-rating__label">Positive</span>
</button>
<button class="rasa-rating__option">
<span class="rasa-rating__icon">😐</span>
<span class="rasa-rating__label">Neutral</span>
</button>
<button class="rasa-rating__option">
<span class="rasa-rating__icon">☹️</span>
<span class="rasa-rating__label">Negative</span>
</button>
</div>
</div>
`);
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: `<rasa-rating text="Rate the answer" options='[
{ "value": "positive", "icon": "😊", "label": "Positive" }
{ "value": "positive", "payload": "/give_positive_feedback" }
]'></rasa-rating>`,
});

Expand All @@ -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 () => {
Expand All @@ -66,8 +52,8 @@ describe('rasa-rating', () => {
const page = await newSpecPage({
components: [RasaRating],
html: `<rasa-rating text="Rate the answer" options='[
{ "value": "positive", "icon": "😊", "label": "Positive" },
{ "value": "neutral", "icon": "😐", "label": "Neutral" }
{ "value": "positive", "payload": "/give_positive_feedback" },
{ "value": "neutral", "payload": "/give_neutral_feedback" }
]'></rasa-rating>`,
});

Expand All @@ -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: `<rasa-rating text="How would you rate this answer?" options='[
{ "value": "positive", "payload": "/give_positive_feedback" }
]' message="We appreciate your feedback!"></rasa-rating>`,
});

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: `<rasa-rating text="Rate this answer" options='[
{ "value": "positive", "payload": "/give_positive_feedback" }
]'></rasa-rating>`,
});

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
});
});
29 changes: 17 additions & 12 deletions packages/ui/src/components/rating/rating.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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);
Expand Down Expand Up @@ -93,7 +98,7 @@ export class RasaRating {
return (
<div class="rasa-rating">
{this.hasVoted ? (
<p class="rasa-rating__thank-you">{this.thankYouMessage}</p> // Thank-you message from Rasa
<p class="rasa-rating__thank-you">{this.message}</p> // Dynamic message from Rasa
) : (
<div>
<p class="rasa-rating__text">{this.text}</p>
Expand All @@ -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)}
></button>
))}
</div>
Expand Down
15 changes: 8 additions & 7 deletions packages/ui/src/components/rating/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
26 changes: 16 additions & 10 deletions packages/ui/src/rasa-chatbot-widget/rasa-chatbot-widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -402,16 +402,22 @@ export class RasaChatbotWidget {
<rasa-carousel elements={message.elements}></rasa-carousel>
</chat-message>
);
case MESSAGE_TYPES.RATING:
return (
<chat-message sender={message.sender} key={key} timestamp={message.timestamp}>
<rasa-rating
text={message.text}
options={JSON.stringify(message.options)}
onRatingSelected={(event) => console.log("Rating selected:", event.detail.value)}
></rasa-rating>
</chat-message>
);
case MESSAGE_TYPES.RATING:
return (
<chat-message sender={message.sender} key={key} timestamp={message.timestamp}>
<rasa-rating
text={message.text}
options={JSON.stringify(message.options)}
message={message.message} // ✅ Pass the message field dynamically
onRatingSelected={(event) => {
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)
}}
></rasa-rating>
</chat-message>
);

}
}

Expand Down

0 comments on commit 8c1f1be

Please sign in to comment.