FredrikOseberg / react-chatbot-kit

MIT License
325 stars 156 forks source link

How to trigger the ActionProvider after a specific question? #29

Closed didacus closed 3 years ago

didacus commented 3 years ago

Hi there,

On my prototype, I ask users personal questions, such as their name and address. Those are difficult answers to predict, so I can't generate triggers on the MessageParser to execute the next question using the ActionProvider. Is there a way to execute the ActionProvider after a specific question?

I really appreciate any help you can provide.

FredrikOseberg commented 3 years ago

Hi. You can create a widget that collects name and address via a form, and then use the actionprovider in the widget to trigger on submit. Similar to how it's done in the Flightbot airport selector here: https://fredrikoseberg.github.io/react-chatbot-kit-docs/ (scroll to bottom).

Otherwise, you can implement a catch all in your message parser:

parse = () => {
   if (rule) {
       this.actionProvider.handleSomething()
   }

   this.actionProvider.catchMessages()
}

Then you can trigger an action in your catch all in the action provider:

catchMessages() {
    this.setState(state => {
          // find the last bot message

          if (lastMessage.includes("name") {
               this.actionProvider.handleSomeAction()
          }
    })
}
didacus commented 3 years ago

@FredrikOseberg, thank you. I will have a look at this now. Let's see if I can get it working. 👍

didacus commented 3 years ago

Okay, this is not the cleanest option, but I am no expert on this. As suggest by @FredrikOseberg you should create a catch-all in the message parser:

      //Catch all
      if (lowercase) {
        this.actionProvider.handleUserMessage(message);
      }

For my solution, you will need to add a new parameter to the question that you want to trigger an action in ActionProvider:

    const msg2 = this.createChatBotMessage(
      "Let’s get to know each other. What’s your name?",
      {
        delay: 2000,
        withAvatar: true,
        content: "name", // Name in this case
      }
    );

Finally, you will add to the logic ActionProvide that will save the user input based on the content parameter you are answering to and trigger the necessary action you require:

  handleUserMessage = () => {
    var lastMessage = "";
    this.setState((state) => {
      lastMessage = state.messages[state.messages.length - 2].content;   

      switch (lastMessage) {
        case "name":
          this.handleFlat();
          break;
        case "flat":
          this.handleEmail();
          break;
        case "email":
          this.handleTerms();
      }

      return state;
    });
  };

I am sure developers will find a much better way to deal with this. After a lot of trial and error, this + @FredrikOseberg suggestion work just fine for a prototype.

Thank you @FredrikOseberg

amanirshad commented 1 year ago

@didacus this is indeed a better workaround for such use cases.