Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add initial implementation (tsx, css) for rating component #97

Merged
merged 7 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions e2e/cypress/fixtures/chatbotWidgetData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const userInputs = {
videoMessage: 'Video',
quickRepliesUserReply: 'hyperlink',
errorConnectionSocketioTest: 'Connection',
ratingMessage: 'Rating',
} as const;

type TUserInputsType = typeof userInputs;
Expand Down Expand Up @@ -139,6 +140,15 @@ const botResponses = {
hyperlink: {
text: 'For more information, visit [Google Website](https://www.google.com/).',
},
Rating: {
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' },
],
},
};

const widgetProps = {
Expand Down
13 changes: 13 additions & 0 deletions packages/react/dist/RasaRating.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/react/dist/RasaRating.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions packages/react/dist/types/RasaRating.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { RasaRating as RasaRatingElement } from "@rasahq/chat-widget-ui/dist/components/rasa-rating.js";
import type { EventName, StencilReactComponent } from '@stencil/react-output-target/runtime';
type RasaRatingEvents = {
onRatingSelected: EventName<CustomEvent<{
value: string;
}>>;
};
declare const RasaRating: StencilReactComponent<RasaRatingElement, RasaRatingEvents>;
export default RasaRating;
25 changes: 25 additions & 0 deletions packages/react/lib/components/stencil-generated/RasaRating.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use client';

/**
* This file was automatically generated by the Stencil React Output Target.
* Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.
*/

/* eslint-disable */

import { RasaRating as RasaRatingElement, defineCustomElement as defineRasaRating } from "@rasahq/chat-widget-ui/dist/components/rasa-rating.js";
import type { EventName, StencilReactComponent } from '@stencil/react-output-target/runtime';
import { createComponent } from '@stencil/react-output-target/runtime';
import React from 'react';

type RasaRatingEvents = { onRatingSelected: EventName<CustomEvent<{ value: string }>> };

const RasaRating: StencilReactComponent<RasaRatingElement, RasaRatingEvents> = /*@__PURE__*/ createComponent<RasaRatingElement, RasaRatingEvents>({
tagName: 'rasa-rating',
elementClass: RasaRatingElement,
react: React,
events: { onRatingSelected: 'ratingSelected' } as RasaRatingEvents,
defineCustomElement: defineRasaRating
});

export default RasaRating;
6 changes: 4 additions & 2 deletions packages/sdk/src/connection-strategy/HTTPConnection.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
HttpResponse,
HttpTextResponse,
HttpVideoResponse,
HttpRatingResponse,
} from '../types/server-response.types';

import { RESPONSE_MESSAGE_TYPES } from '../constants';
Expand Down Expand Up @@ -40,14 +41,15 @@ export function isHttpQuickReplyResponse(response: HttpResponse): response is Ht

export function hasCustomAttribute(
response: HttpResponse,
): response is HttpCarouselResponse | HttpVideoResponse | HttpAccordionResponse | HttpFileDownloadResponse {
): response is HttpCarouselResponse | HttpVideoResponse | HttpAccordionResponse | HttpFileDownloadResponse | HttpRatingResponse {
return (
'custom' in response &&
response.custom !== undefined &&
(response.custom.type === RESPONSE_MESSAGE_TYPES.CAROUSEL ||
response.custom.type === RESPONSE_MESSAGE_TYPES.VIDEO ||
response.custom.type === RESPONSE_MESSAGE_TYPES.ACCORDION ||
response.custom.type === RESPONSE_MESSAGE_TYPES.FILE_DOWNLOAD)
response.custom.type === RESPONSE_MESSAGE_TYPES.FILE_DOWNLOAD ||
response.custom.type === RESPONSE_MESSAGE_TYPES.RATING)
);
}

Expand Down
1 change: 1 addition & 0 deletions packages/sdk/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export const RESPONSE_MESSAGE_TYPES = {
FILE_DOWNLOAD: "file_download",
VIDEO: "video",
IMAGE: "image",
RATING: "rating",
} as const;

export const SESSION_STORAGE_KEYS = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export const MESSAGE_TYPES = {
TEXT: "text",
QUICK_REPLY: "quickReply",
SESSION_DIVIDER: "sessionDivider",
RATING: "rating",
} as const;
10 changes: 9 additions & 1 deletion packages/sdk/src/message-parser/types/parsed-message.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ export interface AccordionMessage extends BaseMessage {
elements: { title: string; text: string; link?: string }[];
}

export interface RatingMessage extends BaseMessage {
type: typeof MESSAGE_TYPES.RATING;
text: string;
options: { value: string; icon: string; label: string }[];
}


export type Message =
| AccordionMessage
| CarouselMessage
Expand All @@ -71,4 +78,5 @@ export type Message =
| SessionDivider
| QuickReplyMessage
| TextMessage
| VideoMessage;
| VideoMessage
| RatingMessage;
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
QuickReplyResponse,
TextResponse,
VideoResponse,
RatingResponse,
} from '../../types/server-response.types';
import { CustomErrorClass, ErrorSeverity } from '../../errors';

Expand All @@ -21,6 +22,7 @@ const messageTypeMap = {
fileDownload: (msg: any): msg is FileDownloadResponse => msg?.type === RESPONSE_MESSAGE_TYPES.FILE_DOWNLOAD,
video: (msg: any): msg is VideoResponse => msg?.type === RESPONSE_MESSAGE_TYPES.VIDEO,
text: (msg: any): msg is TextResponse => msg.text && msg.type === undefined,
rating: (msg: any): msg is RatingResponse => msg?.type === RESPONSE_MESSAGE_TYPES.RATING,
};

export const determineMessageType = (message: unknown): keyof MessageParsersReturnTypes => {
Expand Down
26 changes: 26 additions & 0 deletions packages/sdk/src/message-parser/utils/message-parsers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type {
QuickReplyMessage,
TextMessage,
VideoMessage,
RatingMessage,
} from '../types';
import {
AccordionResponse,
Expand All @@ -15,6 +16,7 @@ import {
QuickReplyResponse,
TextResponse,
VideoResponse,
RatingResponse,
} from '../../types/server-response.types';

import { MESSAGE_TYPES } from '../constants';
Expand Down Expand Up @@ -177,4 +179,28 @@ describe('MessageParsers', () => {

expect(MessageParsers.video(videoResponse, sender)).toEqual(expected);
});

it('rating message correctly parsed', () => {
const ratingResponse: RatingResponse = {
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' },
],
};
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' },
],
};

expect(MessageParsers.rating(ratingResponse, sender)).toEqual(expected);
});
});
9 changes: 9 additions & 0 deletions packages/sdk/src/message-parser/utils/message-parsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
QuickReplyMessage,
TextMessage,
VideoMessage,
RatingMessage,
} from '../types/parsed-message.types';
import {
AccordionResponse,
Expand All @@ -15,6 +16,7 @@ import {
QuickReplyResponse,
TextResponse,
VideoResponse,
RatingResponse,
} from '../../types/server-response.types';

import { MESSAGE_TYPES } from '../constants/message.constants';
Expand Down Expand Up @@ -82,6 +84,13 @@ export const MessageParsers = {
src: video_url,
timestamp,
}),
rating: (message: RatingResponse, sender: SenderType): RatingMessage => ({
sender,
type: MESSAGE_TYPES.RATING,
text: message.text,
options: message.options,
timestamp: message.timestamp,
}),
};

export type MessageParsersType = typeof MessageParsers;
Expand Down
17 changes: 15 additions & 2 deletions packages/sdk/src/types/server-response.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ export interface CarouselResponse extends BaseMessageResponse {
elements: { image_url: string; text: string; link?: string }[];
}

export interface RatingResponse extends BaseMessageResponse {
type: typeof RESPONSE_MESSAGE_TYPES.RATING;
text: string;
options: { value: string; icon: string; label: string }[];
}

export interface QuickReplyResponse extends BaseMessageResponse {
text?: string;
quick_replies: { content_type: string; payload: string; title: string; isSelected?: boolean }[];
Expand Down Expand Up @@ -82,14 +88,20 @@ export interface HttpQuickReplyResponse extends BaseMessageResponse {
buttons: { payload: string; title: string }[];
}

export interface HttpRatingResponse extends BaseMessageResponse {
recipient_id: string;
custom: RatingResponse;
}

export type HttpResponse =
| HttpTextResponse
| HttpImageResponse
| HttpCarouselResponse
| HttpVideoResponse
| HttpAccordionResponse
| HttpFileDownloadResponse
| HttpQuickReplyResponse;
| HttpQuickReplyResponse
| HttpRatingResponse;

export type MessageResponse =
| TextResponse
Expand All @@ -98,4 +110,5 @@ export type MessageResponse =
| CarouselResponse
| QuickReplyResponse
| FileDownloadResponse
| VideoResponse;
| VideoResponse
| RatingResponse;
48 changes: 48 additions & 0 deletions packages/ui/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,16 @@ export namespace Components {
*/
"quickReplyId": string;
}
interface RasaRating {
/**
* List of rating options
*/
"options": string | { value: string; icon: string; label: string }[];
/**
* Instructional text for the rating component
*/
"text": string;
}
interface RasaSessionDivider {
/**
* Session start datetime
Expand Down Expand Up @@ -509,6 +519,10 @@ export interface RasaQuickReplyCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLRasaQuickReplyElement;
}
export interface RasaRatingCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLRasaRatingElement;
}
export interface RasaTextCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLRasaTextElement;
Expand Down Expand Up @@ -722,6 +736,23 @@ declare global {
prototype: HTMLRasaQuickReplyElement;
new (): HTMLRasaQuickReplyElement;
};
interface HTMLRasaRatingElementEventMap {
"ratingSelected": { value: 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;
addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
removeEventListener<K extends keyof HTMLRasaRatingElementEventMap>(type: K, listener: (this: HTMLRasaRatingElement, ev: RasaRatingCustomEvent<HTMLRasaRatingElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;
removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
}
var HTMLRasaRatingElement: {
prototype: HTMLRasaRatingElement;
new (): HTMLRasaRatingElement;
};
interface HTMLRasaSessionDividerElement extends Components.RasaSessionDivider, HTMLStencilElement {
}
var HTMLRasaSessionDividerElement: {
Expand Down Expand Up @@ -787,6 +818,7 @@ declare global {
"rasa-image": HTMLRasaImageElement;
"rasa-image-message": HTMLRasaImageMessageElement;
"rasa-quick-reply": HTMLRasaQuickReplyElement;
"rasa-rating": HTMLRasaRatingElement;
"rasa-session-divider": HTMLRasaSessionDividerElement;
"rasa-text": HTMLRasaTextElement;
"rasa-text-message": HTMLRasaTextMessageElement;
Expand Down Expand Up @@ -1262,6 +1294,20 @@ declare namespace LocalJSX {
*/
"quickReplyId"?: string;
}
interface RasaRating {
/**
* Event emitted when a rating is selected
*/
"onRatingSelected"?: (event: RasaRatingCustomEvent<{ value: string }>) => void;
/**
* List of rating options
*/
"options"?: string | { value: string; icon: string; label: string }[];
/**
* Instructional text for the rating component
*/
"text"?: string;
}
interface RasaSessionDivider {
/**
* Session start datetime
Expand Down Expand Up @@ -1355,6 +1401,7 @@ declare namespace LocalJSX {
"rasa-image": RasaImage;
"rasa-image-message": RasaImageMessage;
"rasa-quick-reply": RasaQuickReply;
"rasa-rating": RasaRating;
"rasa-session-divider": RasaSessionDivider;
"rasa-text": RasaText;
"rasa-text-message": RasaTextMessage;
Expand Down Expand Up @@ -1388,6 +1435,7 @@ declare module "@stencil/core" {
"rasa-image": LocalJSX.RasaImage & JSXBase.HTMLAttributes<HTMLRasaImageElement>;
"rasa-image-message": LocalJSX.RasaImageMessage & JSXBase.HTMLAttributes<HTMLRasaImageMessageElement>;
"rasa-quick-reply": LocalJSX.RasaQuickReply & JSXBase.HTMLAttributes<HTMLRasaQuickReplyElement>;
"rasa-rating": LocalJSX.RasaRating & JSXBase.HTMLAttributes<HTMLRasaRatingElement>;
"rasa-session-divider": LocalJSX.RasaSessionDivider & JSXBase.HTMLAttributes<HTMLRasaSessionDividerElement>;
"rasa-text": LocalJSX.RasaText & JSXBase.HTMLAttributes<HTMLRasaTextElement>;
"rasa-text-message": LocalJSX.RasaTextMessage & JSXBase.HTMLAttributes<HTMLRasaTextMessageElement>;
Expand Down
Loading