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

fix: made some changes and fixes #27

Merged
merged 1 commit into from
Jul 12, 2024
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
20 changes: 12 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,13 @@ function onBeforeRender(instance, setInstance) {
}
```

### Custom responses
### User defined responses

This component is also capable of managing custom responses. To do so, you need to pass a `renderCustomResponse` function as a prop. This function should return a React component that will render the content for the specific message for that response. You should make sure that the `WebChatContainer` component does not get unmounted in the middle of the life of your application because it will lose all custom responses that were previously received by web chat.
This component is also capable of managing user defined responses. To do so, you need to pass a `renderUserDefinedResponse` function as a render prop. This function should return a React component that will render the content for the specific message for that response. You should make sure that the `WebChatContainer` component does not get unmounted in the middle of the life of your application because it will lose all user defined responses that were previously received by web chat.

You should treat the `renderUserDefinedResponse` prop like any typical React render prop; it is different from the `userDefinedResponse` event or a typical event handler. The event is fired only once when web chat initially receives the response from the server. The `renderUserDefinedResponse` prop however is called every time the App re-renders and it should return an up-to-date React component for the provided message item just like the render function would for a typical React component.

Note: in web chat 8.2.0, the custom response event was renamed from `customResponse` to `userDefinedResponse`. If this library detects you are using a prior version of web chat, it will use the `customResponse` event instead of `userDefinedResponse`.

```javascript
import React from 'react';
Expand All @@ -111,14 +115,14 @@ import { WebChatContainer } from '@ibm-watson/assistant-web-chat-react';
const webChatOptions = { /* Web chat options */ };

function App() {
return <WebChatContainer renderCustomResponse={renderCustomResponse} config={webChatOptions} />;
return <WebChatContainer renderUserDefinedResponse={renderUserDefinedResponse} config={webChatOptions} />;
}

function renderCustomResponse(event) {
// The event here will contain details for each custom response that needs to be rendered.
function renderUserDefinedResponse(event) {
// The event here will contain details for each user defined response that needs to be rendered.
// The "user_defined_type" property is just an example; it is not required. You can use any other property or
// condition you want here. This makes it easier to handle different response types if you have more than
// one custom response type.
// one user defined response type.
if (event.data.message.user_defined && event.data.message.user_defined.user_defined_type === 'my-custom-type') {
return <div>My custom content</div>
}
Expand Down Expand Up @@ -164,7 +168,7 @@ function App() {

### WebChatContainer API

The `WebChatContainer` function is a functional component that will load and render an instance of web chat when it is mounted and destroy that instance when unmounted. If the web chat configuration options change, it will also destroy the previous web chat and create a new one with the new configuration. It can also manage React portals for custom responses.
The `WebChatContainer` function is a functional component that will load and render an instance of web chat when it is mounted and destroy that instance when unmounted. If the web chat configuration options change, it will also destroy the previous web chat and create a new one with the new configuration. It can also manage React portals for user defined responses.

Note that this component will call the [web chat render](https://web-chat.global.assistant.watson.cloud.ibm.com/docs.html?to=api-instance-methods#render) method for you. You do not need to call it yourself. You can use the `onBeforeRender` or `onAfterRender` prop to execute operations before or after render is called.

Expand All @@ -178,7 +182,7 @@ Note that this component will call the [web chat render](https://web-chat.global
| instanceRef | No | MutableRefObject | A convenience prop that is a reference to the web chat instance. This component will set the value of this ref using the `current` property when the instance has been created. |
| onBeforeRender | No | function | This is a callback function that is called after web chat has been loaded and before the `render` function is called. This function is passed a single argument which is the instance of web chat that was loaded. This function can be used to obtain a reference to the web chat instance if you want to make use of the instance methods that are available. |
| onAfterRender | No | function | This is a callback function that is called after web chat has been loaded and after the `render` function is called. This function is passed a single argument which is the instance of web chat that was loaded. This function can be used to obtain a reference to the web chat instance if you want to make use of the instance methods that are available. |
| renderCustomResponse | No | function | This function is a callback function that will be called by this container to render custom responses. If this prop is provided, then the container will listen for custom response events from web chat and will generate a React portal for each event. This function will be called once during component render for each custom response event. This function takes two arguments. The first is the [custom response event](https://web-chat.global.assistant.watson.cloud.ibm.com/docs.html?to=api-events#customresponse) that triggered the custom response. The second is a convenience argument that is the instance of web chat. The function should return a `ReactNode` that renders the custom content for the response. |
| renderUserDefinedResponse | No | function | This function is a callback function that will be called by this container to render user defined responses. If this prop is provided, then the container will listen for user defined response events from web chat and will generate a React portal for each event. This function will be called once during component render for each user defined response event. This function takes two arguments. The first is the [user defined response event](https://web-chat.global.assistant.watson.cloud.ibm.com/docs.html?to=api-events#userDefinedResponse) that triggered the user defined response. The second is a convenience argument that is the instance of web chat. The function should return a `ReactNode` that renders the user defined content for the response. |

`WebChatCustomElement` inherits all of the props from `WebChatContainer`. It also has the following additional optional props.

Expand Down
26 changes: 26 additions & 0 deletions package-lock.json

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

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"@types/proper-url-join": "^2.1.1",
"@types/react": "^16.14.17",
"@types/react-dom": "^16.9.14",
"@types/semver-compare": "^1.0.3",
"@typescript-eslint/eslint-plugin": "^5.30.6",
"@typescript-eslint/parser": "^5.30.6",
"babel-core": "^6.26.3",
Expand Down Expand Up @@ -83,5 +84,8 @@
],
"publishConfig": {
"access": "public"
},
"dependencies": {
"semver-compare": "^1.0.0"
}
}
97 changes: 0 additions & 97 deletions src/CustomResponsePortalsContainer.tsx

This file was deleted.

87 changes: 87 additions & 0 deletions src/UserDefinedResponsePortalsContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/**
* (C) Copyright IBM Corp. 2022, 2024.
*
* Licensed under the MIT License (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
*/

import React, { ReactNode } from 'react';
import ReactDOM from 'react-dom';
import { UserDefinedResponseEvent } from './types/UserDefinedResponseEvent';
import { WebChatInstance } from './types/WebChatInstance';
import { RenderUserDefinedResponse } from './WebChatContainer';

interface UserDefinedResponsePortalsContainer {
/**
* The instance of a web chat that this component will register listeners on.
*/
webChatInstance: WebChatInstance;

/**
* The function that this component will use to request the actual React content to display for each user defined
* response.
*/
renderResponse: RenderUserDefinedResponse;

/**
* The list of events that were fired that contain all the responses to render.
*/
userDefinedResponseEvents: UserDefinedResponseEvent[];
}

/**
* This is a utility component that is used to manage all the user defined responses that are rendered by web chat.
* When a user defined response message is received by web chat, it will fire a "userDefinedResponse" event that
* provides an HTML element to which your application can attach user defined content. React portals are a mechanism
* that allows you to render a component in your React application but attach that component to the HTML element
* that was provided by web chat.
*
* This component will render a portal for each user defined response. The contents of that portal will be
* determined by calling the provided "renderResponse" render prop.
*/
function UserDefinedResponsePortalsContainer({
webChatInstance,
renderResponse,
userDefinedResponseEvents,
}: UserDefinedResponsePortalsContainer) {
// All we need to do to enable the React portals is to render each portal somewhere in your application (it
// doesn't really matter where).
return (
<>
{userDefinedResponseEvents.map(function mapEvent(event, index) {
return (
// eslint-disable-next-line react/no-array-index-key
<UserDefinedResponseComponentPortal key={index} hostElement={event.data.element}>
{renderResponse(event, webChatInstance)}
</UserDefinedResponseComponentPortal>
);
})}
</>
);
}

/**
* This is the component that will attach a React portal to the given host element. The host element is the element
* provided by web chat where your user defined response will be displayed in the DOM. This portal will attach any React
* children passed to it under this component so you can render the response using your own React application. Those
* children will be rendered under the given element where it lives in the DOM.
*/
function UserDefinedResponseComponentPortal({
hostElement,
children,
}: {
hostElement: HTMLElement;
children: ReactNode;
}) {
return ReactDOM.createPortal(children, hostElement);
}

const UserDefinedResponsePortalsContainerExport = React.memo(UserDefinedResponsePortalsContainer);
export { UserDefinedResponsePortalsContainerExport as UserDefinedResponsePortalsContainer };
Loading
Loading